Adds working config and some data
Creates a working configuration for the site. The writeups directory lists the different ctfs and each ctfs list every challenge inside of it. Also adds two ctfs to the writeups used to setup the site.
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
public/
|
||||
ressources/_gen
|
||||
/public/
|
||||
/resources/_gen/
|
||||
.hugo_build.lock
|
||||
|
||||
|
||||
7
content/canary.md
Normal file
7
content/canary.md
Normal file
@@ -0,0 +1,7 @@
|
||||
+++
|
||||
date = '2025-06-23T14:24:30+02:00'
|
||||
draft = true
|
||||
title = 'Canary'
|
||||
+++
|
||||
|
||||
Coming soon.
|
||||
12
content/posts/_index.md
Normal file
12
content/posts/_index.md
Normal file
@@ -0,0 +1,12 @@
|
||||
+++
|
||||
draft = true
|
||||
date = 2025-06-24T14:21:07+02:00
|
||||
title = ""
|
||||
description = ""
|
||||
slug = ""
|
||||
authors = []
|
||||
tags = []
|
||||
categories = []
|
||||
externalLink = ""
|
||||
series = []
|
||||
+++
|
||||
6
content/writeups/2023/htb_university_ctf/_index.md
Normal file
6
content/writeups/2023/htb_university_ctf/_index.md
Normal file
@@ -0,0 +1,6 @@
|
||||
+++
|
||||
date = '2023-12-11T23:00:00+02:00'
|
||||
draft = true
|
||||
title = 'Hack the Box university ctf'
|
||||
+++
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,138 @@
|
||||
+++
|
||||
date = '2023-12-11T23:00:00+02:00'
|
||||
draft = false
|
||||
title = 'Windows of opportunity'
|
||||
tags = [ 'reverse' ]
|
||||
+++
|
||||
|
||||
To look at the writeup in english, click [here](#english).
|
||||
|
||||
# Français
|
||||
## Examen du fichier binaire
|
||||
On nous donne un fichier binaire.
|
||||
|
||||
Un petit `file` pour avoir quelques infos :
|
||||
```
|
||||
windows: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=121c16ba1218dc3686b3cdac4705bc7496fb0fe7, for GNU/Linux 3.2.0, not stripped
|
||||
```
|
||||
|
||||
C'est bien un exécutable qu'il va donc falloir décompiler.
|
||||
On peut faire un `string`, mais pas grand-chose d'intéressant.
|
||||
|
||||
On lance ghidra et on obtient ceci :
|
||||

|
||||
|
||||
Ce code va ajouter deux à deux les valeurs ASCII de l'entrée de l'utilisateur et les comparer à un tableau `arr` stocké quelque part en mémoire.
|
||||
Par exemple : si on entre `ABCD` le programme vas vérifier si `arr` contient `[131, 133, 135]`.
|
||||
|
||||
En examinant la mémoire (j'ai cliqué sur le nom tout simplement.) on trouve ceci :
|
||||

|
||||
|
||||
## Reconstitution du flag
|
||||
|
||||
Il faut donc reconstituer un input valide, pour cela, je sors mon meilleur ami : python
|
||||
```python
|
||||
a = (0x9c, 0x96, 0xbd, 0xaf, 0x93, 0xc3, 0x94, 0x60, 0xa2, 0xd1, 0xc2, 0xcf, 0x9c, 0xa3, 0xa6, 0x68, 0x94, 0xc1, 0xd7, 0xac, 0x96, 0x93, 0x93, 0xd6, 0xa8, 0x9f, 0xd2, 0x94, 0xa7, 0xd6, 0x8f, 0xa0, 0xa3, 0xa1, 0xa3, 0x56, 0x9e)
|
||||
# a est un tuple simulant arr
|
||||
|
||||
def get_pairs(number:int) -> list[str]:
|
||||
# Renvoie toutes les combinaisons de lettre permettant d'obtenir un chiffre (number)
|
||||
combinations = list()
|
||||
for i in range(33, 127):
|
||||
nb2 = number - i
|
||||
if nb2 >= 33 and nb2 <= 126:
|
||||
combinations.append(chr(i) + chr(nb2))
|
||||
return combinations
|
||||
|
||||
def char_series(strings_a:list[str], strings_b:list[str]) -> list[str]:
|
||||
# Permet de concatener les str entre elle si strings_a[i][-1] et strings_b[j][0] identique
|
||||
combinations = list()
|
||||
for i in strings_a:
|
||||
for j in strings_b:
|
||||
if i[-1] == j[0]:
|
||||
combinations.append((i + j[1:]))
|
||||
return combinations
|
||||
|
||||
pairs_of_a = list()
|
||||
for i in a:
|
||||
pairs_of_a.append(get_pairs(i))
|
||||
# On crée toutes les combinaisons de chiffre
|
||||
|
||||
answers = char_series(pairs_of_a[0], pairs_of_a[1])
|
||||
for i in pairs_of_a[2:]:
|
||||
answers = char_series(answers, i)
|
||||
print(answers)
|
||||
# On les met toutes à la suite
|
||||
```
|
||||
|
||||
On fait tourner le programme et on obtient :
|
||||
```python
|
||||
['HTB{4_d00r_cl0s35_bu7_4_w1nd0w_0p3n5!}', 'ISCz5^e/1q`bm/t26^ct8^5^x0oc1v`/q2o4"|', 'JRDy6]f.2paan.u17]ds9]6]y/pb2ua.r1p3#{', 'KQEx7\\g-3ob`o-v08\\er:\\7\\z.qa3tb-s0q2$z', 'LPFw8[h,4nc_p,w/9[fq;[8[{-r`4sc,t/r1%y', 'MOGv9Zi+5md^q+x.:Zgp<Z9Z|,s_5rd+u.s0&x', "NNHu:Yj*6le]r*y-;Yho=Y:Y}+t^6qe*v-t/'w", 'OMIt;Xk)7kf\\s)z,<Xin>X;X~*u]7pf)w,u.(v']
|
||||
```
|
||||
On a bien le flag, mais également d'autres input qui sont également valide.
|
||||
|
||||
# English
|
||||
|
||||
## Examination of the binary file
|
||||
|
||||
We are given a binary file.
|
||||
|
||||
A small `file` to grab some informations :
|
||||
```
|
||||
windows: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=121c16ba1218dc3686b3cdac4705bc7496fb0fe7, for GNU/Linux 3.2.0, not stripped
|
||||
```
|
||||
|
||||
It is an executable so we will have to decompile it.
|
||||
We can run `string`, but nothing interesting.
|
||||
|
||||
We start ghidra and obtain this :
|
||||

|
||||
|
||||
This piece of code will add two by two the ASCII values of the user entry and compare them to an array names `arr` which is stored somewhere in memory.
|
||||
For example : if we enter `ABCD` the programm will check wether or not `arr` contains `[131, 133, 135]`.
|
||||
|
||||
After looking up the memory we find this :
|
||||

|
||||
|
||||
## Flag recreation
|
||||
|
||||
We have to create a valid input, to achieve this I bring my best friend : python
|
||||
```python
|
||||
a = (0x9c, 0x96, 0xbd, 0xaf, 0x93, 0xc3, 0x94, 0x60, 0xa2, 0xd1, 0xc2, 0xcf, 0x9c, 0xa3, 0xa6, 0x68, 0x94, 0xc1, 0xd7, 0xac, 0x96, 0x93, 0x93, 0xd6, 0xa8, 0x9f, 0xd2, 0x94, 0xa7, 0xd6, 0x8f, 0xa0, 0xa3, 0xa1, 0xa3, 0x56, 0x9e)
|
||||
# a is a tuple to simulate arr
|
||||
|
||||
def get_pairs(number:int) -> list[str]:
|
||||
# Returns every combination of letters that creates a number
|
||||
combinations = list()
|
||||
for i in range(33, 127):
|
||||
nb2 = number - i
|
||||
if nb2 >= 33 and nb2 <= 126:
|
||||
combinations.append(chr(i) + chr(nb2))
|
||||
return combinations
|
||||
|
||||
def char_series(strings_a:list[str], strings_b:list[str]) -> list[str]:
|
||||
# Allows to concatenate the strings if strings_a[i][-1] and strings_b[j][0] are identical
|
||||
combinations = list()
|
||||
for i in strings_a:
|
||||
for j in strings_b:
|
||||
if i[-1] == j[0]:
|
||||
combinations.append((i + j[1:]))
|
||||
return combinations
|
||||
|
||||
pairs_of_a = list()
|
||||
for i in a:
|
||||
pairs_of_a.append(get_pairs(i))
|
||||
# We create the list of str for every number of a
|
||||
|
||||
answers = char_series(pairs_of_a[0], pairs_of_a[1])
|
||||
for i in pairs_of_a[2:]:
|
||||
answers = char_series(answers, i)
|
||||
print(answers)
|
||||
# We put them all together
|
||||
```
|
||||
|
||||
We run the programm and we obtain :
|
||||
```python
|
||||
['HTB{4_d00r_cl0s35_bu7_4_w1nd0w_0p3n5!}', 'ISCz5^e/1q`bm/t26^ct8^5^x0oc1v`/q2o4"|', 'JRDy6]f.2paan.u17]ds9]6]y/pb2ua.r1p3#{', 'KQEx7\\g-3ob`o-v08\\er:\\7\\z.qa3tb-s0q2$z', 'LPFw8[h,4nc_p,w/9[fq;[8[{-r`4sc,t/r1%y', 'MOGv9Zi+5md^q+x.:Zgp<Z9Z|,s_5rd+u.s0&x', "NNHu:Yj*6le]r*y-;Yho=Y:Y}+t^6qe*v-t/'w", 'OMIt;Xk)7kf\\s)z,<Xin>X;X~*u]7pf)w,u.(v']
|
||||
```
|
||||
We do get the flag but we also get more inputs that would also be valid.
|
||||
Binary file not shown.
7
content/writeups/2024/404_ctf/_index.md
Normal file
7
content/writeups/2024/404_ctf/_index.md
Normal file
@@ -0,0 +1,7 @@
|
||||
+++
|
||||
date = '2024-05-14T19:00:00+02:00'
|
||||
draft = true
|
||||
title = '404 ctf 2024'
|
||||
+++
|
||||
|
||||
2024 edition of the 404 ctf
|
||||
@@ -0,0 +1,281 @@
|
||||
+++
|
||||
date = '2024-05-14T19:00:00+02:00'
|
||||
draft = false
|
||||
title = 'Reversible engineering'
|
||||
tags = [ "rev" ]
|
||||
+++
|
||||
|
||||
**Mon programme ne fonctionne pas à tout les coups il faut le lancer plusieurs fois pour obtenir le flag si quelqu'un arrive à comprendre pourquoi n'hésitez pas à me contacter sur discord (furtest).**
|
||||
|
||||
# Description
|
||||
|
||||
Après une année éprouvante marquée par les compétitions, vous décidez de rentrer dans votre village natal. C'est avec beaucoup d'émotion que vous apercevez le dojo de votre enfance et décidez de vous y rendre. Votre ancienne sensei vous y attend, le sourire aux lèvres.
|
||||
|
||||
"La clairvoyance est l'arme la plus redoutable du combattant. Anticiper chaque mouvement avant qu'il ne soit lancé, voilà la véritable maîtrise du combat. Relève mon défi et prouve ta valeur."
|
||||
|
||||
Récupérer une archive zip avec netcat contenant un crackme et un token, renvoyer le token avec la solution du crackme à un deuxième serveur, recevoir un flag... Facile. Petit détail : vous avez vingt secondes pour faire tout ça, et le binaire change à chaque essai.
|
||||
|
||||
Connexion :
|
||||
nc challenges.404ctf.fr 31998 > chall.zip
|
||||
nc challenges.404ctf.fr 31999
|
||||
|
||||
|
||||
# Début de la réflexion
|
||||
|
||||
Le but du challenge est de récupérer un binaire, trouver le mot de passe permettant de valider et de renvoyer ce mot de passe pour obtenir le flag.
|
||||
|
||||
On commence par télecharger et analyser quelques binaires à l'aide de ghidra.
|
||||
|
||||
```C
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
int is_different;
|
||||
int return_code;
|
||||
size_t password_size;
|
||||
void *encrypted;
|
||||
undefined8 key_part_1;
|
||||
undefined8 key_part_2;
|
||||
int size;
|
||||
|
||||
if (argc < 2) {
|
||||
puts("J\'ai besoin d\'un argument!");
|
||||
is_different = 1;
|
||||
}
|
||||
else {
|
||||
password_size = strlen(argv[1]);
|
||||
size = (int)password_size;
|
||||
if (size == 16) {
|
||||
key_part_1 = 0x7b3f3a454d58604d;
|
||||
key_part_2 = 0x39485a4069796e5b;
|
||||
encrypted = (void *)encrypt(argv[1]);
|
||||
is_different = memcmp(encrypted,&key_part_1,16);
|
||||
if (is_different == 0) {
|
||||
puts("GG!");
|
||||
return_code = 0;
|
||||
}
|
||||
else {
|
||||
puts("Dommage... Essaie encore!");
|
||||
return_code = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
puts("L'argument doit comporter 16 caractères.");
|
||||
return_code = 1;
|
||||
}
|
||||
}
|
||||
return return_code;
|
||||
}
|
||||
```
|
||||
|
||||
On remarque que le programme est toujours similaire :
|
||||
- On doit entrer un mot de passe de 16 caractères en argument.
|
||||
- Ce mot de passe est chiffré et ce chiffrement est comparé avec une clé.
|
||||
|
||||
Mais il y a de petits changements :
|
||||
- La clé change.
|
||||
- Les opérations exécutées sur le mot de passe changent.
|
||||
|
||||
Analysons également quelques fonctions `encrypt`.
|
||||
```c
|
||||
char * encrypt(char *password)
|
||||
{
|
||||
byte bVar1;
|
||||
byte bVar2;
|
||||
char *encrypted_password;
|
||||
int i;
|
||||
|
||||
encrypted_password = (char *)malloc(16);
|
||||
for (i = 0; i < 0x10; i = i + 1) {
|
||||
bVar1 = password[i];
|
||||
bVar2 = bVar1 ^ (byte)(((int)(uint)bVar1 >> 5 & (int)(uint)bVar1 >> 3 & 1U) << 2) ^
|
||||
(byte)((bVar1 >> 6 & 1) << 2) ^ 0x10;
|
||||
bVar2 = bVar2 ^ (byte)(((uint)(bVar1 >> 7) & (int)(uint)bVar2 >> 2 & 1U) << 5) ^ 0x24;
|
||||
bVar2 = bVar2 ^ (byte)((bVar2 >> 3 & 1) << 2);
|
||||
bVar2 = bVar2 ^ bVar2 * '\x02' & 2 ^ 0x3a;
|
||||
encrypted_password[i] = bVar2 ^ bVar2 >> 3 & 1;
|
||||
}
|
||||
return encrypted_password;
|
||||
}
|
||||
```
|
||||
|
||||
On remarque que le mot de passe est chiffré caractère par caractère, il est donc possible de le bruteforce.
|
||||
|
||||
# Idée
|
||||
|
||||
Mon idée est de récupérer le code de la fonction encrypt grâce à l'API de scripting de ghidra et de m'en servir pour dans un autre programme pour bruteforce le mot de passe.
|
||||
Pour cela, plusieurs choses sont nécessaires.
|
||||
|
||||
## Automatiser le télechargement des binaires
|
||||
|
||||
On écrit un petit script bash qui nous permettra également de lier entre elle toutes les parties du processus.
|
||||
On le complétera plus tard.
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf workdir
|
||||
mkdir workdir
|
||||
cd workdir
|
||||
mkdir ghtest
|
||||
|
||||
timeout 3s nc challenges.404ctf.fr 31998 > chall.zip
|
||||
unzip chall.zip
|
||||
cd ..
|
||||
```
|
||||
|
||||
## Programme principal de bruteforce <div id="bruteforce"></div>
|
||||
|
||||
On écrit un programme en C qui fera des appels à la fonction `encrypt` pour permettre le bruteforce.
|
||||
|
||||
```C
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
char * encrypt(char*);
|
||||
|
||||
int main(void){
|
||||
int count = 0;
|
||||
char passwd[17] = {0};
|
||||
char *res = NULL;
|
||||
int test;
|
||||
long int part1 = {key part 1 here};
|
||||
long int part2 = {key part 2 here};
|
||||
for(int c = 0; c < 16; c++){
|
||||
for(int i = 0; i < 256; ++i){
|
||||
passwd[c] = (char) i;
|
||||
res = encrypt(passwd);
|
||||
if(c < 9){
|
||||
test = memcmp(res, &part1, c+1);
|
||||
}else{
|
||||
test = memcmp(res+8, &part2, c-7);
|
||||
}
|
||||
if(test == 0){
|
||||
count++;
|
||||
printf("%c", (char) i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(count == 16){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
## Récupération de la fonction encrypt
|
||||
|
||||
On utilise python pour décompiler le crackme grâce à l'api de ghidra (headless analyzer) et on stocke le résultat dans deux fichiers :
|
||||
- `decompiled_main.txt` pour pouvoir récupérer la clé
|
||||
- `decompiled_encode.c` qui contient le code pour la fonction `encrypt`
|
||||
(Voir [ici](https://github.com/HackOvert/GhidraSnippets) pour plus d'informations)
|
||||
|
||||
```python
|
||||
from ghidra.app.decompiler import DecompInterface
|
||||
from ghidra.util.task import ConsoleTaskMonitor
|
||||
|
||||
program = getCurrentProgram()
|
||||
ifc = DecompInterface()
|
||||
ifc.openProgram(program)
|
||||
|
||||
f = open("workdir/decompiled_main.txt", "at")
|
||||
g = open("workdir/decompiled_encode.c", "at")
|
||||
g.write("#include <stdlib.h>\n#include <stdint.h>") # On prépare le terrain pour la suite
|
||||
fm = currentProgram.getFunctionManager()
|
||||
funcs = fm.getFunctions(True)
|
||||
for func in funcs:
|
||||
if func.getName() == "FUN_00101169":
|
||||
f.write(ifc.decompileFunction(func, 0, ConsoleTaskMonitor()).getDecompiledFunction().getC())
|
||||
elif func.getName() == "FUN_0010123f":
|
||||
g.write(ifc.decompileFunction(func, 0, ConsoleTaskMonitor()).getDecompiledFunction().getC())
|
||||
f.close()
|
||||
g.close()
|
||||
```
|
||||
|
||||
## Envoie du mot de passe
|
||||
|
||||
On écrit un script python qui permettra d'envoyer le mot de passe une fois qu'il aura été récupéré.
|
||||
Au passage, on vérifie que le mot de passe est bien valide, car parfois, ce n'est pas le cas.
|
||||
|
||||
```python
|
||||
import socket
|
||||
|
||||
passwd_f = open("workdir/passwd.txt")
|
||||
passwd = passwd_f.read()
|
||||
passwd_f.close()
|
||||
token_f = open("workdir/token.txt")
|
||||
token = token_f.read()
|
||||
token_f.close()
|
||||
|
||||
if len(passwd) != 16:
|
||||
print("Fail")
|
||||
quit()
|
||||
|
||||
print(f"Passwd : {passwd}")
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect(("challenges.404ctf.fr", 31999))
|
||||
print(s.recv(4096).decode())
|
||||
token += "\n"
|
||||
s.send(token.encode())
|
||||
print(s.recv(4096).decode())
|
||||
passwd += "\n"
|
||||
s.send(passwd.encode())
|
||||
print(s.recv(4096).decode())
|
||||
```
|
||||
|
||||
## Problème de la clé
|
||||
|
||||
On tombe rapidement sur un problème, il faut insérer la clé dans la fonction main du programme, on écrit donc un programme python permettant de générer le programme en C qui sera ensuite compilé avec `decompiled_encode.c` pour la fonction encrypt. (Il y a sûrement une autre façon de le faire.)
|
||||
Je ne remets pas tout le programme en C juste les lignes modifiées, vous pouvez le revoir [ici](#bruteforce).
|
||||
|
||||
```python
|
||||
encoded_out = open("workdir/decompiled_main.txt")
|
||||
content = encoded_out.readlines()
|
||||
|
||||
|
||||
main = """
|
||||
#{ coupé pour la visibilité }
|
||||
long int part1 = """ + content[20][17:-1] + """
|
||||
long int part2 = """ + content[21][17:-1] + """
|
||||
#{ coupé pour la visibilité }
|
||||
"""
|
||||
encoded_out.close()
|
||||
|
||||
main_file = open("workdir/main.c", "wt")
|
||||
main_file.write(main)
|
||||
main_file.close()
|
||||
```
|
||||
|
||||
|
||||
# Lien entre les parties
|
||||
|
||||
Il faut maintenant lier toutes les parties entre elles pour cela, on va modifier le script bash.
|
||||
- On exécute le headless analyze de ghidra avec le script de décompilation.
|
||||
- On utilise sed pour modifier un peu la fonction `encrypt` et pour que le compilateur soit content.
|
||||
- On génére le programme principal de bruteforce.
|
||||
- On compile tout puis on exécute en récupérant le mot de passe dans `passwd.txt`
|
||||
- On envoie le mot de passe et on affiche le flag avec `send.py`
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf workdir
|
||||
mkdir workdir
|
||||
cd workdir
|
||||
mkdir ghtest
|
||||
|
||||
timeout 3s nc challenges.404ctf.fr 31998 > chall.zip
|
||||
unzip chall.zip
|
||||
cd ..
|
||||
{ghidra_path}/support/analyzeHeadless workdir/ghtest testghidra -import workdir/crackme.bin -postScript decompile.py
|
||||
sed -i 's/byte/char/g' workdir/decompiled_encode.c
|
||||
sed -i 's/void/char/g' workdir/decompiled_encode.c
|
||||
sed -i 's/FUN_0010123f/encode/g' workdir/decompiled_encode.c
|
||||
python3 bruteforce_gen.py
|
||||
gcc workdir/main.c workdir/decompiled_encode.c -o workdir/bruteforce
|
||||
./workdir/bruteforce > workdir/passwd.txt
|
||||
python3 send.py
|
||||
```
|
||||
|
||||
Plus qu'à exécuter le programme et hop là, c'est réussi.
|
||||
@@ -0,0 +1,3 @@
|
||||
set confirm off
|
||||
set pagination off
|
||||
new-ui mi2 /dev/pts/4
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
char * encode(char *);
|
||||
|
||||
int main(void){
|
||||
char passwd[17] = {0};
|
||||
char *res = NULL;
|
||||
int test;
|
||||
long int part1 = 0x7b3f3a454d58604d;
|
||||
long int part2 = 0x39485a4069796e5b;
|
||||
for(int c = 0; c < 16; c++){
|
||||
for(int i = 0; i < 256; ++i){
|
||||
passwd[c] = (char) i;
|
||||
res = encode(passwd);
|
||||
if(c < 9){
|
||||
test = memcmp(res, &part1, c+1);
|
||||
}else{
|
||||
test = memcmp(res+8, &part2, c-7);
|
||||
}
|
||||
if(test == 0){
|
||||
printf("%c", (char) i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
encoded_out = open("workdir/decompiled_main.txt")
|
||||
content = encoded_out.readlines()
|
||||
|
||||
|
||||
main = """
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
char * encode(char*);
|
||||
|
||||
int main(void){
|
||||
int count = 0;
|
||||
char passwd[17] = {0};
|
||||
char *res = NULL;
|
||||
int test;
|
||||
long int part1 = """ + content[20][17:-1] + """
|
||||
long int part2 = """ + content[21][17:-1] + """
|
||||
for(int c = 0; c < 16; c++){
|
||||
for(int i = 0; i < 256; ++i){
|
||||
passwd[c] = (char) i;
|
||||
res = encode(passwd);
|
||||
if(c < 9){
|
||||
test = memcmp(res, &part1, c+1);
|
||||
}else{
|
||||
test = memcmp(res+8, &part2, c-7);
|
||||
}
|
||||
if(test == 0){
|
||||
count++;
|
||||
printf("%c", (char) i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(count == 16){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
"""
|
||||
encoded_out.close()
|
||||
|
||||
#encoder = open("workdir/decompiled_encode.c")
|
||||
#main += encoder.read()
|
||||
#encoder.close()
|
||||
|
||||
main_file = open("workdir/main.c", "wt")
|
||||
main_file.write(main)
|
||||
main_file.close()
|
||||
@@ -0,0 +1,19 @@
|
||||
from ghidra.app.decompiler import DecompInterface
|
||||
from ghidra.util.task import ConsoleTaskMonitor
|
||||
|
||||
program = getCurrentProgram()
|
||||
ifc = DecompInterface()
|
||||
ifc.openProgram(program)
|
||||
|
||||
f = open("workdir/decompiled_main.txt", "at")
|
||||
g = open("workdir/decompiled_encode.c", "at")
|
||||
g.write("#include <stdlib.h>\n#include <stdint.h>")
|
||||
fm = currentProgram.getFunctionManager()
|
||||
funcs = fm.getFunctions(True) # True means 'forward'
|
||||
for func in funcs:
|
||||
if func.getName() == "FUN_00101169":
|
||||
f.write(ifc.decompileFunction(func, 0, ConsoleTaskMonitor()).getDecompiledFunction().getC())
|
||||
elif func.getName() == "FUN_0010123f":
|
||||
g.write(ifc.decompileFunction(func, 0, ConsoleTaskMonitor()).getDecompiledFunction().getC())
|
||||
f.close()
|
||||
g.close()
|
||||
@@ -0,0 +1,24 @@
|
||||
import socket
|
||||
|
||||
passwd_f = open("workdir/passwd.txt")
|
||||
passwd = passwd_f.read()
|
||||
passwd_f.close()
|
||||
token_f = open("workdir/token.txt")
|
||||
token = token_f.read()
|
||||
token_f.close()
|
||||
|
||||
if len(passwd) != 16:
|
||||
print("Fail")
|
||||
quit()
|
||||
|
||||
print(f"Passwd : {passwd}")
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect(("challenges.404ctf.fr", 31999))
|
||||
print(s.recv(4096).decode())
|
||||
token += "\n"
|
||||
s.send(token.encode())
|
||||
print(s.recv(4096).decode())
|
||||
passwd += "\n"
|
||||
s.send(passwd.encode())
|
||||
print(s.recv(4096).decode())
|
||||
#nc challenges.404ctf.fr 31999
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -rf workdir
|
||||
mkdir workdir
|
||||
cd workdir
|
||||
mkdir ghtest
|
||||
|
||||
timeout 3s nc challenges.404ctf.fr 31998 > chall.zip
|
||||
#if (( `file chall.zip` = 'chall.zip : empty' )); then
|
||||
# exit 1
|
||||
#fi
|
||||
unzip chall.zip
|
||||
cd ..
|
||||
/home/furtest/application/ghidra_10.4_PUBLIC/support/analyzeHeadless workdir/ghtest testghidra -import workdir/crackme.bin -postScript decompile.py
|
||||
sed -i 's/byte/char/g' workdir/decompiled_encode.c
|
||||
sed -i 's/void/char/g' workdir/decompiled_encode.c
|
||||
sed -i 's/FUN_0010123f/encode/g' workdir/decompiled_encode.c
|
||||
#sed -i 's/long/char */g' workdir/decompiled_encode.c
|
||||
python3 bruteforce_gen.py
|
||||
gcc workdir/main.c workdir/decompiled_encode.c -o workdir/bruteforce
|
||||
./workdir/bruteforce > workdir/passwd.txt
|
||||
python3 send.py
|
||||
#rm -rf 'workdir'
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,29 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
char * encode(long param_1)
|
||||
|
||||
{
|
||||
char bVar1;
|
||||
char bVar2;
|
||||
char *pvVar3;
|
||||
int local_c;
|
||||
|
||||
pvVar3 = malloc(0x10);
|
||||
for (local_c = 0; local_c < 0x10; local_c = local_c + 1) {
|
||||
bVar1 = *(char *)(param_1 + local_c);
|
||||
bVar2 = bVar1 ^ (char)(((int)(uint)bVar1 >> 6 & (int)(uint)bVar1 >> 5 & 1U) << 3) ^
|
||||
(char)((bVar1 >> 6 & 1) << 2);
|
||||
bVar2 = bVar2 ^ (char)((bVar2 >> 2 & 1) << 5) ^ 4;
|
||||
bVar2 = bVar2 ^ (char)(((int)(uint)bVar2 >> 5 & (int)(uint)bVar2 >> 4 & 1U) << 3);
|
||||
bVar2 = bVar2 ^ (char)(((int)(uint)bVar2 >> 3 & bVar2 & 1) << 2) ^ 1 ^
|
||||
(char)((bVar1 >> 6 & 1) << 4) ^ 0x10;
|
||||
bVar2 = bVar2 ^ (bVar1 >> 7 & (char)((int)(uint)bVar2 >> 6) & 1) * '\x02';
|
||||
bVar2 = bVar2 ^ (char)(((int)(uint)bVar2 >> 3 & (int)(uint)bVar2 >> 1 & 1U) << 5) ^ 8;
|
||||
bVar2 = bVar2 ^ (char)((bVar2 >> 3 & 1) << 5);
|
||||
*(char *)((long)local_c + (long)pvVar3) =
|
||||
bVar2 ^ (char)(((uint)(bVar1 >> 7) & (int)(uint)bVar2 >> 4 & 1U) << 2) ^ 0x10 ^
|
||||
(bVar2 >> 5) << 7 ^ 2;
|
||||
}
|
||||
return pvVar3;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
undefined8 FUN_00101169(int param_1,long param_2)
|
||||
|
||||
{
|
||||
int iVar1;
|
||||
undefined8 uVar2;
|
||||
size_t sVar3;
|
||||
void *__s1;
|
||||
undefined8 local_28;
|
||||
undefined8 local_20;
|
||||
int local_c;
|
||||
|
||||
if (param_1 < 2) {
|
||||
puts("J\'ai besoin d\'un argument!");
|
||||
uVar2 = 1;
|
||||
}
|
||||
else {
|
||||
sVar3 = strlen(*(char **)(param_2 + 8));
|
||||
local_c = (int)sVar3;
|
||||
if (local_c == 0x10) {
|
||||
local_28 = 0x46f0b8f4eff0544d;
|
||||
local_20 = 0x5fb844f850e415f3;
|
||||
__s1 = (void *)FUN_0010123f(*(undefined8 *)(param_2 + 8));
|
||||
iVar1 = memcmp(__s1,&local_28,0x10);
|
||||
if (iVar1 == 0) {
|
||||
puts("GG!");
|
||||
uVar2 = 0;
|
||||
}
|
||||
else {
|
||||
puts("Dommage... Essaie encore!");
|
||||
uVar2 = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
puts(&DAT_00102028);
|
||||
uVar2 = 1;
|
||||
}
|
||||
}
|
||||
return uVar2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FILE_INFO>
|
||||
<BASIC_INFO>
|
||||
<STATE NAME="CONTENT_TYPE" TYPE="string" VALUE="Program" />
|
||||
<STATE NAME="PARENT" TYPE="string" VALUE="/" />
|
||||
<STATE NAME="FILE_ID" TYPE="string" VALUE="7f0118e054057717349298" />
|
||||
<STATE NAME="FILE_TYPE" TYPE="int" VALUE="0" />
|
||||
<STATE NAME="READ_ONLY" TYPE="boolean" VALUE="false" />
|
||||
<STATE NAME="NAME" TYPE="string" VALUE="crackme.bin" />
|
||||
</BASIC_INFO>
|
||||
</FILE_INFO>
|
||||
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
VERSION=1
|
||||
/
|
||||
NEXT-ID:0
|
||||
MD5:d41d8cd98f00b204e9800998ecf8427e
|
||||
@@ -0,0 +1,5 @@
|
||||
VERSION=1
|
||||
/
|
||||
00000000:crackme.bin:7f0118e054057717349298
|
||||
NEXT-ID:1
|
||||
MD5:d41d8cd98f00b204e9800998ecf8427e
|
||||
@@ -0,0 +1,2 @@
|
||||
IADD:00000000:/crackme.bin
|
||||
IDSET:/crackme.bin:7f0118e054057717349298
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FILE_INFO>
|
||||
<BASIC_INFO>
|
||||
<STATE NAME="OWNER" TYPE="string" VALUE="furtest" />
|
||||
</BASIC_INFO>
|
||||
</FILE_INFO>
|
||||
@@ -0,0 +1,4 @@
|
||||
VERSION=1
|
||||
/
|
||||
NEXT-ID:0
|
||||
MD5:d41d8cd98f00b204e9800998ecf8427e
|
||||
@@ -0,0 +1,4 @@
|
||||
VERSION=1
|
||||
/
|
||||
NEXT-ID:0
|
||||
MD5:d41d8cd98f00b204e9800998ecf8427e
|
||||
@@ -0,0 +1,4 @@
|
||||
VERSION=1
|
||||
/
|
||||
NEXT-ID:0
|
||||
MD5:d41d8cd98f00b204e9800998ecf8427e
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
char * encode(char*);
|
||||
|
||||
int main(void){
|
||||
int count = 0;
|
||||
char passwd[17] = {0};
|
||||
char *res = NULL;
|
||||
int test;
|
||||
long int part1 = 0x46f0b8f4eff0544d;
|
||||
long int part2 = 0x5fb844f850e415f3;
|
||||
for(int c = 0; c < 16; c++){
|
||||
for(int i = 0; i < 256; ++i){
|
||||
passwd[c] = (char) i;
|
||||
res = encode(passwd);
|
||||
if(c < 9){
|
||||
test = memcmp(res, &part1, c+1);
|
||||
}else{
|
||||
test = memcmp(res+8, &part2, c-7);
|
||||
}
|
||||
if(test == 0){
|
||||
count++;
|
||||
printf("%c", (char) i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(count == 16){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
vKOTc7OqH2sgkS7l
|
||||
@@ -0,0 +1 @@
|
||||
15e49d93918b820dc0d629ea65303531
|
||||
5
content/writeups/_index.md
Normal file
5
content/writeups/_index.md
Normal file
@@ -0,0 +1,5 @@
|
||||
+++
|
||||
date = '2025-06-23T14:23:22+02:00'
|
||||
draft = true
|
||||
title = 'Writeups'
|
||||
+++
|
||||
28
layouts/writeups/chall.html
Normal file
28
layouts/writeups/chall.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{{ $page := . }}
|
||||
{{ $tag := index $page.Params.tags 0 }}
|
||||
{{ with $tag }}
|
||||
{{ $prefix := lower (substr . 0 3) }}
|
||||
{{ $colorMap := dict
|
||||
"rev" "#6366f1"
|
||||
"pwn" "#ef4444"
|
||||
"web" "#3b82f6"
|
||||
"cry" "#10b981"
|
||||
"mis" "#f59e0b"
|
||||
"for" "#8b5cf6"
|
||||
"bin" "#ec4899"
|
||||
"net" "#06b6d4"
|
||||
"ste" "#f472b6"
|
||||
"mob" "#a855f7"
|
||||
}}
|
||||
{{ $color := index $colorMap $prefix | default "#9ca3af" }} {{/* fallback: gray-400 */}}
|
||||
|
||||
<li style="margin-bottom: 0.75em;">
|
||||
<span style="background-color: {{ $color }}; padding: 0em 0.7em; border-radius: 0.3em; color: #fff; font-size: 0.85em; margin-right: 0.5em;">
|
||||
<a href="{{ "/tags/" | relLangURL }}{{ . | urlize }}" style="color: inherit; text-decoration: none;">
|
||||
{{ . }}
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<a class="title" href="{{ $page.Params.externalLink | default $page.RelPermalink }}">{{ $page.Title }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
4
layouts/writeups/li.html
Normal file
4
layouts/writeups/li.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<li>
|
||||
<span class="date">{{ .Date | time.Format (.Site.Params.dateFormat | default "January 2, 2006" ) }}</span>
|
||||
<a class="title" href="{{ .Params.externalLink | default .RelPermalink }}">{{ .Title }}</a>
|
||||
</li>
|
||||
29
layouts/writeups/list.html
Normal file
29
layouts/writeups/list.html
Normal file
@@ -0,0 +1,29 @@
|
||||
{{ define "title" }}
|
||||
{{ title (i18n (lower .Title)) | default .Title }} · {{ .Site.Title }}
|
||||
{{ end }}
|
||||
{{ define "content" }}
|
||||
<section class="container list">
|
||||
<header>
|
||||
<h1 class="title">
|
||||
<a class="title-link" href="{{ .Permalink | safeURL }}">
|
||||
{{ title (i18n (lower .Title)) | default .Title }}
|
||||
</a>
|
||||
</h1>
|
||||
</header>
|
||||
{{ .Content }}
|
||||
<ul>
|
||||
{{ if eq .File.Path "writeups/_index.md" }}
|
||||
{{- range .Sections -}}
|
||||
{{- .Render "li" -}}
|
||||
{{- end -}}
|
||||
{{ else }}
|
||||
<h2 class="title">Solved challenges</h2>
|
||||
{{- range .Paginator.Pages -}}
|
||||
{{- .Render "chall" -}}
|
||||
{{- end -}}
|
||||
{{ end }}
|
||||
</ul>
|
||||
|
||||
{{ partial "pagination.html" . }}
|
||||
</section>
|
||||
{{ end }}
|
||||
56
layouts/writeups/single.html
Normal file
56
layouts/writeups/single.html
Normal file
@@ -0,0 +1,56 @@
|
||||
{{ define "title" }}
|
||||
{{ .Title }} · {{ .Site.Title }}
|
||||
{{ end }}
|
||||
{{ define "content" }}
|
||||
<section class="container post">
|
||||
<article>
|
||||
<header>
|
||||
<div class="post-title">
|
||||
<h1 class="title">
|
||||
<a class="title-link" href="{{ .Permalink | safeURL }}">
|
||||
{{ .Title }}
|
||||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="post-meta">
|
||||
<div class="date">
|
||||
<span class="posted-on">
|
||||
<i class="fa-solid fa-calendar" aria-hidden="true"></i>
|
||||
<time datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}">
|
||||
{{ .Date | time.Format (.Site.Params.dateFormat | default "January 2, 2006" ) }}
|
||||
</time>
|
||||
</span>
|
||||
<span class="reading-time">
|
||||
<i class="fa-solid fa-clock" aria-hidden="true"></i>
|
||||
{{ i18n "reading_time" .ReadingTime }}
|
||||
</span>
|
||||
</div>
|
||||
{{ with .GetTerms "authors" }}{{ partial "taxonomy/authors.html" . }}{{ end }}
|
||||
{{ with .GetTerms "categories" }}{{ partial "taxonomy/categories.html" . }}{{ end }}
|
||||
{{ with .GetTerms "tags" }}{{ partial "taxonomy/tags.html" . }}{{ end }}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="post-content">
|
||||
{{ if .Params.featuredImage }}
|
||||
<img src="{{ .Params.featuredImage | relURL }}" alt="Featured image"/>
|
||||
{{ end }}
|
||||
{{ .Content }}
|
||||
</div>
|
||||
|
||||
|
||||
<footer>
|
||||
{{ partial "posts/series.html" . }}
|
||||
{{ partial "posts/disqus.html" . }}
|
||||
{{ partial "posts/commento.html" . }}
|
||||
{{ partial "posts/utterances.html" . }}
|
||||
{{ partial "posts/giscus.html" . }}
|
||||
{{ partial "posts/mastodon.html" . }}
|
||||
{{ partial "posts/telegram.html" . }}
|
||||
{{ partial "posts/cusdis.html" . }}
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
{{ partial "posts/math.html" . }}
|
||||
</section>
|
||||
{{ end }}
|
||||
BIN
static/images/pp.png
Normal file
BIN
static/images/pp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 162 KiB |
Reference in New Issue
Block a user