<style>
img[alt=chall-sc] {
display: block;
margin: 0 auto;
width: 100em;
}
p {
text-align: justify;
}
p::first-line {
text-indent: 0;
}
</style>
# University CTF 2024: Binary Badlands Reverse Engineering Writeup (Bahasa Indonesia)
## CryoWarmup

Diberikan ELF 64-bit, decompile ELFnya
### main
```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE v4[56]; // [rsp+0h] [rbp-40h] BYREF
unsigned __int64 v5; // [rsp+38h] [rbp-8h]
v5 = __readfsqword(0x28u);
printf("Enter the password: ");
__isoc99_scanf("%49s", v4);
if ( (unsigned int)validate_password(v4) )
puts("Access granted!");
else
puts("Access denied!");
return 0;
}
```
### generate_key
```c
size_t __fastcall generate_key(const char *a1)
{
size_t result; // rax
int i; // [rsp+1Ch] [rbp-14h]
for ( i = 0; ; ++i )
{
result = strlen(a1);
if ( i >= result )
break;
a1[i] = (a1[i] ^ 0x2A) + 5;
}
return result;
}
```
### validate_password
```c
_BOOL8 __fastcall validate_password(const char *a1)
{
char s2[8]; // [rsp+17h] [rbp-49h] BYREF
char v3; // [rsp+1Fh] [rbp-41h]
char dest[56]; // [rsp+20h] [rbp-40h] BYREF
unsigned __int64 v5; // [rsp+58h] [rbp-8h]
v5 = __readfsqword(0x28u);
*(_QWORD *)s2 = 0x625F491E53532047LL;
v3 = 0;
strcpy(dest, a1);
generate_key(dest);
return strcmp(dest, s2) == 0;
}
```
Challenge ini merupakan challenge dalam bentuk kuis. Berikut pertanyaan-pertanyaan yang diberikan:
1. What libc function is used to check if the password is correct?
2. What is the size of the password buffer, based on the argument to scanf?
3. What is the name of the function that modifies the user's input?
4. What would be the result of applying the operation from this function to a string containing one character, 'B'? Provide your answer as a hex number, e.g. 0x4f.
5. What is printed if the password is correct?
6. How long is the password, based on the value that the user's input is compared against (not including the final null byte)?
7. What is the password?
Jawab:
1. Fungsi libc yang ngecek password ada di fungsi `validate_password`
```c
return strcmp(dest, s2) == 0;
```
Jadi fungsi libcnya yang ngecek password adalah `strcmp`
2. Password buffernya adalah variabel `v4`. Input Size berdasarkan argumen di fungsi `scanf` adalah 49 bytes
```c
__isoc99_scanf("%49s", v4);
```
3. Fungsi yang ngemodify user input adalah fungsi `validate_password` pada fungsi `main`
```c
if ( (unsigned int)validate_password(v4) )
```
4. Perhatikan fungsi `generate_key`:
```c
size_t __fastcall generate_key(const char *a1)
{
size_t result; // rax
int i; // [rsp+1Ch] [rbp-14h]
for ( i = 0; ; ++i )
{
result = strlen(a1);
if ( i >= result )
break;
a1[i] = (a1[i] ^ 0x2A) + 5;
}
return result;
}
```
Langsung saja apply untuk `B`
```python
>>> hex((ord('B') ^ 0x2a) + 5)
'0x6d'
```
Jadi, returned character dalam bentuk hexadecimal ketika kita menginput `B` adalah `0x6d`
5. Access granted!
```c
if ( (unsigned int)validate_password(v4) )
puts("Access granted!");
```
6. Panjang passwordnya 8 bytes
```c
_BOOL8 __fastcall validate_password(const char *a1)
{
char s2[8]; // s2 itu passwordnya
/// --- ///
*(_QWORD *)s2 = 0x625F491E53532047LL;
/// --- ///
```
7. Reverse algoritma generate_key untuk mendapatkan passwordnya. Passwordnya adalah `h1dd3npw`
```python
#!/usr/bin/env python3
from pwn import p64
def sol(target):
pw = ""
for x in target:
init = chr((x - 5) ^ 0x2A)
pw += init
return pw
target = p64(0x625F491E53532047)
pw = sol(target)
print(f"{pw}")
```
## SecurityInTheFront

Diberikan index.html
### index.html
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Space Prison Management</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #10141e;
color: #ffffff;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
text-align: center;
background: #1e2a38;
padding: 20px;
border-radius: 8px;
width: 400px;
}
.input-group,
.cell-group {
margin: 15px 0;
}
input {
width: calc(100% - 20px);
padding: 8px;
border: none;
border-radius: 4px;
margin-bottom: 10px;
}
button {
padding: 10px;
width: 100%;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button.access-btn {
background: #5cdb95;
color: #10141e;
}
.cell-group {
display: none;
}
.cell-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
.cell {
padding: 15px;
background-color: #f95d66;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
}
.cell span {
margin-bottom: 10px;
}
.cell button {
background: transparent;
color: white;
border: 2px solid white;
cursor: pointer;
transition: background-color 0.5s ease;
}
.cell button.opened {
background-color: #5cdb95;
border-color: #5cdb95;
}
</style>
</head>
<body>
<div class="container">
<div id="access-form" class="input-group">
<h2>Enter Access Code</h2>
<input type="text" id="access-user" placeholder="Guard Name" />
<input type="password" id="access-code" placeholder="Access Code" />
<button class="access-btn" onclick="checkCredentials()">Submit</button>
</div>
<div id="cell-list" class="cell-group">
<h2>Cell Management</h2>
<div class="cell-grid">
<div class="cell">
<span>Aurion Flux</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Zyra Talon</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Kryon Vale</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Vex Drakon</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Nyx Solaris</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Lazari Void</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Empty</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Kael Xypher</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Cypher Lux</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Empty</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Dax Zenith</span>
<button onclick="openCell(this)">Open</button>
</div>
<div class="cell">
<span>Lyra Quasar</span>
<button onclick="openCell(this)">Open</button>
</div>
</div>
</div>
</div>
<script>
function activate() {
document.getElementById('cell-list').style.display = 'block';
document.getElementById('access-form').style.display = 'none';
}
async function checkCredentials(){var t=document.getElementById("access-user").value, r=document.getElementById("access-code").value;c1="NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm",c2="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",n1=[5,6,7,8,9,0,1,2,3,4],n2="0123456789";var n=(e,t,r)=>e.reduce(((e,r,n)=>r.apply(e,t[n])),r),c=[""],i=String.prototype.split,a=Array.prototype.join,o=Array.prototype.filter,p=Array.prototype.map,l=String.prototype.slice,y=String.prototype.repeat,u=Array.prototype.indexOf,s=Array.prototype.reduce,d=Array.prototype.reverse,h=function(e){return this==e},f=function(e){return indexedDB.cmp(this,e)},A=String.prototype.charAt;if([[[i,p,f,h],[c,[e=>-1==u.call(c2,e)?e:c1[u.call(c2,e)]],[["n","q","z","v","a"]],[0]],t],[[l,y,i,p,o,f,h],[[0,4],[3],c,[e=>-1==u.call(c2,e)?e:c1[u.call(c2,e)]],[(e,t)=>t%3==1],[["G","U","{","O"]],[0]],r],[[l,function(){return encodeURI(this)},l,function(e){return parseInt(this,e)},function(e){return this^e},h],[[-1],[],[-2],[16],[96],[29]],r],[[i,s,h],[c,[e=>e+e,1],[16777216]],r],[[y,i,p,s,h],[[21],c,[e=>n1[u.call(n2,e)]],[(e,t)=>e+h.apply(t,[8]),0],[63]],r],[[i,o,p,d,a,h],[c,[(e,t)=>~u.call([4,11,13,14,16,17,20,22],t)],[e=>c1[u.call(c2,e)]],[],["-"],["E-X-U-P-J-C-Q-S"]],r],[[function(){return Array.from(this)},f,h],[[],[["_"]],[0]],new Set(n([l,i,d,o],[[12,16],c,[],[(e,t)=>~u.apply([0,3],[t])]],r))],[[i,d,o,function(){return this.slice(2,this.length).concat(this.slice(0,2))},d,a,h],[c,[],[(e,t)=>~u.apply([18,13,4,16,15],[t])],[],[],[""],["ncrnt"]],r],[[A,h],[[6],["0"]],r]].reduce(((e,t)=>e&&n.apply(void 0,t)),!0)){var v=new Uint8Array((new TextEncoder).encode(r)),g=new Uint8Array(await crypto.subtle.digest("SHA-256",v)),m=new Uint8Array([9,87,39,96,151,202,140,186,120,235,167,229,47,231,6,212,77,205,58,14,248,104,169,79,116,140,236,98,126,26,100,120]);0==indexedDB.cmp(g,m)?activate():alert("User is not authorized. This incident will be reported.")}else alert("User is not authorized.")}
function openCell(button) {
button.classList.add("opened");
button.disabled = true;
}
document
.getElementById("access-code")
.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
checkCredentials();
}
});
</script>
</body>
</html>
```
Diminta memasukan username dan password (Guard Name dan Access Code)

Algoritma pengecekan username dan passwordnya terdapat pada javascript yang ada di `index.html` tersebut
```js
function activate() {
document.getElementById('cell-list').style.display = 'block';
document.getElementById('access-form').style.display = 'none';
}
async function checkCredentials(){var t=document.getElementById("access-user").value, r=document.getElementById("access-code").value;c1="NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm",c2="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",n1=[5,6,7,8,9,0,1,2,3,4],n2="0123456789";var n=(e,t,r)=>e.reduce(((e,r,n)=>r.apply(e,t[n])),r),c=[""],i=String.prototype.split,a=Array.prototype.join,o=Array.prototype.filter,p=Array.prototype.map,l=String.prototype.slice,y=String.prototype.repeat,u=Array.prototype.indexOf,s=Array.prototype.reduce,d=Array.prototype.reverse,h=function(e){return this==e},f=function(e){return indexedDB.cmp(this,e)},A=String.prototype.charAt;if([[[i,p,f,h],[c,[e=>-1==u.call(c2,e)?e:c1[u.call(c2,e)]],[["n","q","z","v","a"]],[0]],t],[[l,y,i,p,o,f,h],[[0,4],[3],c,[e=>-1==u.call(c2,e)?e:c1[u.call(c2,e)]],[(e,t)=>t%3==1],[["G","U","{","O"]],[0]],r],[[l,function(){return encodeURI(this)},l,function(e){return parseInt(this,e)},function(e){return this^e},h],[[-1],[],[-2],[16],[96],[29]],r],[[i,s,h],[c,[e=>e+e,1],[16777216]],r],[[y,i,p,s,h],[[21],c,[e=>n1[u.call(n2,e)]],[(e,t)=>e+h.apply(t,[8]),0],[63]],r],[[i,o,p,d,a,h],[c,[(e,t)=>~u.call([4,11,13,14,16,17,20,22],t)],[e=>c1[u.call(c2,e)]],[],["-"],["E-X-U-P-J-C-Q-S"]],r],[[function(){return Array.from(this)},f,h],[[],[["_"]],[0]],new Set(n([l,i,d,o],[[12,16],c,[],[(e,t)=>~u.apply([0,3],[t])]],r))],[[i,d,o,function(){return this.slice(2,this.length).concat(this.slice(0,2))},d,a,h],[c,[],[(e,t)=>~u.apply([18,13,4,16,15],[t])],[],[],[""],["ncrnt"]],r],[[A,h],[[6],["0"]],r]].reduce(((e,t)=>e&&n.apply(void 0,t)),!0)){var v=new Uint8Array((new TextEncoder).encode(r)),g=new Uint8Array(await crypto.subtle.digest("SHA-256",v)),m=new Uint8Array([9,87,39,96,151,202,140,186,120,235,167,229,47,231,6,212,77,205,58,14,248,104,169,79,116,140,236,98,126,26,100,120]);0==indexedDB.cmp(g,m)?activate():alert("User is not authorized. This incident will be reported.")}else alert("User is not authorized.")}
function openCell(button) {
button.classList.add("opened");
button.disabled = true;
}
document
.getElementById("access-code")
.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
checkCredentials();
}
});
```
Dapat dilihat bahwa javascript tersebut diobfuscate. Langsung saja saya rapikan dengan javascript beautifier (https://beautifier.io/)
```js
function activate() {
document.getElementById('cell-list').style.display = 'block';
document.getElementById('access-form').style.display = 'none';
}
async function checkCredentials() {
var t = document.getElementById("access-user").value,
r = document.getElementById("access-code").value;
c1 = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm", c2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", n1 = [5, 6, 7, 8, 9, 0, 1, 2, 3, 4], n2 = "0123456789";
var n = (e, t, r) => e.reduce(((e, r, n) => r.apply(e, t[n])), r),
c = [""],
i = String.prototype.split,
a = Array.prototype.join,
o = Array.prototype.filter,
p = Array.prototype.map,
l = String.prototype.slice,
y = String.prototype.repeat,
u = Array.prototype.indexOf,
s = Array.prototype.reduce,
d = Array.prototype.reverse,
h = function(e) {
return this == e
},
f = function(e) {
return indexedDB.cmp(this, e)
},
A = String.prototype.charAt;
if ([
[
[i, p, f, h],
[c, [e => -1 == u.call(c2, e) ? e : c1[u.call(c2, e)]],
[
["n", "q", "z", "v", "a"]
],
[0]
], t
],
[
[l, y, i, p, o, f, h],
[
[0, 4],
[3], c, [e => -1 == u.call(c2, e) ? e : c1[u.call(c2, e)]],
[(e, t) => t % 3 == 1],
[
["G", "U", "{", "O"]
],
[0]
], r
],
[
[l, function() {
return encodeURI(this)
}, l, function(e) {
return parseInt(this, e)
}, function(e) {
return this ^ e
}, h],
[
[-1],
[],
[-2],
[16],
[96],
[29]
], r
],
[
[i, s, h],
[c, [e => e + e, 1],
[16777216]
], r
],
[
[y, i, p, s, h],
[
[21], c, [e => n1[u.call(n2, e)]],
[(e, t) => e + h.apply(t, [8]), 0],
[63]
], r
],
[
[i, o, p, d, a, h],
[c, [(e, t) => ~u.call([4, 11, 13, 14, 16, 17, 20, 22], t)],
[e => c1[u.call(c2, e)]],
[],
["-"],
["E-X-U-P-J-C-Q-S"]
], r
],
[
[function() {
return Array.from(this)
}, f, h],
[
[],
[
["_"]
],
[0]
], new Set(n([l, i, d, o], [
[12, 16], c, [],
[(e, t) => ~u.apply([0, 3], [t])]
], r))
],
[
[i, d, o, function() {
return this.slice(2, this.length).concat(this.slice(0, 2))
}, d, a, h],
[c, [],
[(e, t) => ~u.apply([18, 13, 4, 16, 15], [t])],
[],
[],
[""],
["ncrnt"]
], r
],
[
[A, h],
[
[6],
["0"]
], r
]
].reduce(((e, t) => e && n.apply(void 0, t)), !0)) {
var v = new Uint8Array((new TextEncoder).encode(r)),
g = new Uint8Array(await crypto.subtle.digest("SHA-256", v)),
m = new Uint8Array([9, 87, 39, 96, 151, 202, 140, 186, 120, 235, 167, 229, 47, 231, 6, 212, 77, 205, 58, 14, 248, 104, 169, 79, 116, 140, 236, 98, 126, 26, 100, 120]);
0 == indexedDB.cmp(g, m) ? activate() : alert("User is not authorized. This incident will be reported.")
} else alert("User is not authorized.")
}
function openCell(button) {
button.classList.add("opened");
button.disabled = true;
}
document
.getElementById("access-code")
.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
checkCredentials();
}
});
```
Rumit, sulit untuk dimengerti. Saya rename functionsnya kemudian berikan comments. Hasilnya:
```js
function activate() {
document.getElementById('cell-list').style.display = 'block';
document.getElementById('access-form').style.display = 'none';
}
async function checkCredentials() {
var username = document.getElementById("access-user").value;
var password = document.getElementById("access-code").value;
var c1 = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm";
var c2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var n1 = [5, 6, 7, 8, 9, 0, 1, 2, 3, 4];
var n2 = "0123456789";
var chainFuncs = (funcs, argsForFuncs, initialVal) =>
funcs.reduce((acc, currFunc, idx) => currFunc.apply(acc, argsForFuncs[idx]), initialVal);
var emptyArray = [""];
var splitStr = String.prototype.split;
var joinArr = Array.prototype.join;
var filterArr = Array.prototype.filter;
var mapArr = Array.prototype.map;
var sliceStr = String.prototype.slice;
var repeatStr = String.prototype.repeat;
var indexOfArr = Array.prototype.indexOf;
var reduceArr = Array.prototype.reduce;
var reverseArr = Array.prototype.reverse;
var charAtStr = String.prototype.charAt;
var h = function(e) { return this == e; };
var f = function(e) { return indexedDB.cmp(this, e); };
// inti algoritmanya -> ngetransform input trus ngecek kalo udah sesuai kriteria atau belum
var conditions = [
// 1st set of transformations on username
[
[splitStr, mapArr, f, h],
[
emptyArray,
[e => indexOfArr.call(c2, e) === -1 ? e : c1[indexOfArr.call(c2, e)]],
[["n", "q", "z", "v", "a"]],
[0]
],
username
],
// 2nd set of transformations on password
[
[sliceStr, repeatStr, splitStr, mapArr, filterArr, f, h],
[
[0, 4],
[3],
emptyArray,
[ch => indexOfArr.call(c2, ch) === -1 ? ch : c1[indexOfArr.call(c2, ch)]],
[(e, idx) => idx % 3 == 1],
[["G", "U", "{", "O"]],
[0]
],
password
],
// 3rd set: additional complex transformations on password (encoding, parsing, XOR)
[
[
sliceStr,
function() { return encodeURI(this); },
sliceStr,
function(e) { return parseInt(this, e); },
function(e) { return this ^ e; },
h
],
[
[-1],
[],
[-2],
[16],
[96],
[29]
],
password
],
// 4th set: doubling characters, large numeric conditions on password
[
[splitStr, reduceArr, h],
[
emptyArray,
[e => e + e, 1],
[16777216]
],
password
],
// 5th set: repeated transformations and numeric mapping
[
[repeatStr, splitStr, mapArr, reduceArr, h],
[
[21],
emptyArray,
[e => n1[indexOfArr.call(n2, e)]],
[(e, t) => e + h.apply(t, [8]), 0],
[63]
],
password
],
// 6th set: filtering, mapping with ROT13, and joined with '-'
[
[splitStr, filterArr, mapArr, reverseArr, joinArr, h],
[
emptyArray,
[(e, t) => ~indexOfArr.call([4, 11, 13, 14, 16, 17, 20, 22], t)],
[e => c1[indexOfArr.call(c2, e)]],
[],
["-"],
["E-X-U-P-J-C-Q-S"]
],
password
],
// 7th set: converting password into a Set after transformations
[
[
function() { return Array.from(this); },
f,
h
],
[
[],
[["_"]],
[0]
],
new Set(
n(
[sliceStr, splitStr, reverseArr, filterArr],
[
[12, 16],
emptyArray,
[],
[(e, t) => ~indexOfArr.apply([0, 3], [t])]
],
password
)
)
],
// 8th set: complex slicing, rotating, filtering, reversing steps
[
[
splitStr,
reverseArr,
filterArr,
function() {
return this.slice(2, this.length).concat(this.slice(0, 2));
},
reverseArr,
joinArr,
h
],
[
emptyArray,
[],
[(e, t) => ~indexOfArr.apply([18, 13, 4, 16, 15], [t])],
[],
[],
[""],
["ncrnt"]
],
password
],
// 9th set: character-at based check
[
[charAtStr, h],
[
[6],
["0"]
],
password
]
];
// jika pengecekan password valid
var allChecksPass = conditions.reduce((prev, current) => prev && chainFuncs.apply(undefined, current), true);
if (allChecksPass) {
// compute sha-256 dari passwordnya
var passBytes = new TextEncoder().encode(password);
var hashBuffer = await crypto.subtle.digest("SHA-256", passBytes);
var passwordHash = new Uint8Array(hashBuffer);
var knownHash = new Uint8Array([9, 87, 39, 96, 151, 202, 140, 186, 120, 235, 167, 229, 47, 231, 6, 212, 77, 205, 58, 14, 248, 104, 169, 79, 116, 140, 236, 98, 126, 26, 100, 120]);
if (indexedDB.cmp(passwordHash, knownHash) === 0) {
activate();
} else {
alert("User is not authorized. This incident will be reported.");
}
} else {
alert("User is not authorized.");
}
}
function openCell(button) {
button.classList.add("opened");
button.disabled = true;
}
document.getElementById("access-code").addEventListener("keydown", function(event) {
if (event.key === "Enter") {
checkCredentials();
}
});
```
Pengecekan usernamenya menggunakan algoritma `ROT13`. Langsung saja saya reverse algoritmanya
```python
#!/usr/bin/env python3
from z3 import *
user = [Int(f'p{i}') for i in range(5)]
solver = Solver()
def rot13(x):
return If(And(x >= 65, x <= 90), ((x - 65 + 13) % 26) + 65,
If(And(x >= 97, x <= 122), ((x - 97 + 13) % 26) + 97, x))
solver.add(rot13(user[0]) == ord('n'))
solver.add(rot13(user[1]) == ord('q'))
solver.add(rot13(user[2]) == ord('z'))
solver.add(rot13(user[3]) == ord('v'))
solver.add(rot13(user[4]) == ord('a'))
if solver.check() == sat:
model = solver.model()
user = ''.join(chr(model[user[i]].as_long()) for i in range(5))
print(user)
```
Didapatkan usernamenya `admin`. Untuk algoritma passwordnya cukup ribet, namun masih feasible untuk disatisfy dengan `z3` python module
```python
#!/usr/bin/env python3
from z3 import *
pw = [Int(f'p{i}') for i in range(24)]
solver = Solver()
for i in range(24):
solver.add(pw[i] >= 32, pw[i] <= 126)
def rot13(x):
return If(And(x >= 65, x <= 90), ((x - 65 + 13) % 26) + 65,
If(And(x >= 97, x <= 122), ((x - 97 + 13) % 26) + 97, x))
solver.add(rot13(pw[0]) == ord('U'))
solver.add(rot13(pw[1]) == ord('G'))
solver.add(rot13(pw[2]) == ord('O'))
solver.add(rot13(pw[3]) == ord('{'))
solver.add(pw[23] == ord('}'))
solver.add(pw[6] == ord('0'))
solver.add(Sum([If(pw[i] == ord('3'), 1, 0) for i in range(24)]) == 3)
rot13_indices = [4, 11, 13, 14, 16, 17, 20, 22]
rot13_val = [ord(c) for c in "EXUPJCQS"]
for idx, value in zip(rot13_indices, reversed(rot13_val)):
solver.add(rot13(pw[idx]) == value)
solver.add(pw[12] == ord('_'))
solver.add(pw[15] == ord('_'))
solver.add(pw[5] == ord('r'))
solver.add(pw[10] == ord('n'))
solver.add(pw[19] == ord('c'))
solver.add(pw[7] == ord('n'))
solver.add(pw[8] == ord('t'))
solver.add(pw[9] == ord('3'))
solver.add(pw[18] == ord('3'))
solver.add(pw[21] == ord('3'))
if solver.check() == sat:
model = solver.model()
pw = ''.join(chr(model[pw[i]].as_long()) for i in range(24))
print(pw)
```
Didapatkan passwordnya yang merupakan flag, yakni `HTB{Fr0nt3nD_PW_CH3cK3R}`
## ColossalBreach

Sama seperti CryoWarmup, challenge ini merupakan challenge dalam bentuk kuis. Berikut pertanyaan-pertanyaan yang diberikan:
1. Who is the module's author?
2. What is the name of the function used to register keyboard events?
3. What is the name of the function that converts keycodes to strings?
4. What file does the module create to store logs? Provide the full path
5. What message does the module print when imported?
6. What is the XOR key used to obfuscate the keys? (e.g. 0x01, 0x32)
7. What is the password entered for 'adam'?
Diberikan Kernel Module `brainstorm.ko` dan `logs`. Decompile Kernel Modulenya
### spy_init
```c
int __cdecl spy_init()
{
dentry *dir; // rax
_fentry__();
LODWORD(dir) = -22;
if ( (unsigned int)codes <= 2 )
{
dir = (dentry *)debugfs_create_dir("spyyy", 0LL);
subdir = dir;
if ( (unsigned __int64)dir <= 0xFFFFFFFFFFFFF000LL )
{
if ( dir )
{
if ( debugfs_create_file("keys", 256LL, dir, 0LL, &keys_fops) )
{
register_keyboard_notifier(&spy_blk);
printk(&unk_C11);
LODWORD(dir) = 0;
return (int)dir;
}
debugfs_remove(subdir);
}
LODWORD(dir) = -2;
}
}
return (int)dir;
}
```
### spy_cb
```c
// bad sp value at call has been detected, the output may be wrong!
__int64 spy_cb()
{
_DWORD *v0; // rdx
size_t v2; // rax
size_t v3; // rdx
char *v4; // rcx
char *v5; // rax
size_t v6; // rbx
char *v7; // rdi
char buf[8]; // [rsp+0h] [rbp-1Ch] BYREF
int v9; // [rsp+8h] [rbp-14h]
unsigned __int64 v10; // [rsp+Ch] [rbp-10h]
_fentry__();
v10 = __readgsqword(0x28u);
v9 = 0;
*(_QWORD *)buf = 0LL;
if ( v0[2] )
{
keycode_to_string(v0[5], v0[3], buf, codes);
v2 = strnlen(buf, 0xCuLL);
v3 = v2;
if ( v2 > 0xC )
spy_cb_cold(buf, 12LL, v2);
if ( v2 == 12 )
JUMPOUT(0x2E3LL);
if ( v2 )
{
v4 = buf;
v5 = &buf[v2];
do
*v4++ ^= 0x19u;
while ( v5 != v4 );
v6 = buf_pos + v3;
v7 = &keys_buf[buf_pos];
if ( buf_pos + v3 > 0x3FFF )
{
v6 = v3;
v7 = keys_buf;
}
strncpy(v7, buf, v3);
buf_pos = v6;
if ( codes )
{
keys_buf[v6] = 10;
buf_pos = v6 + 1;
}
}
}
return 1LL;
}
```
### keys_read
```c
ssize_t __fastcall keys_read(file *filp, char *buffer, size_t len, loff_t *offset)
{
__int64 v4; // rdx
__int64 v5; // rcx
_fentry__(filp, buffer, len, offset);
return simple_read_from_buffer(buffer, v4, v5, keys_buf, buf_pos);
}
```
### keycode_to_string
```c
void __fastcall keycode_to_string(__int64 keycode, __int64 shift_mask, char *buf, __int64 type)
{
char *v4; // rdx
int v5; // ecx
__int64 v6; // rdi
const char *v7; // rcx
_fentry__(keycode, shift_mask, buf, type);
if ( v5 == 1 )
{
if ( (unsigned int)(keycode - 1) <= 0x2FD )
snprintf(v4, 0xCuLL, "%x %x", keycode, shift_mask);
}
else if ( v5 == 2 )
{
if ( (unsigned int)(keycode - 1) <= 0x2FD )
snprintf(v4, 0xCuLL, "%d %d", keycode, shift_mask);
}
else if ( !v5 && (unsigned int)(keycode - 1) <= 0x76 )
{
v6 = (int)keycode;
if ( (_DWORD)shift_mask == 1 )
v7 = us_keymap[v6][1];
else
v7 = us_keymap[v6][0];
snprintf(v4, 0xCuLL, "%s", v7);
}
}
```
### spy_cb_cold
```c
void __noreturn spy_cb_cold()
{
fortify_panic("strnlen");
fortify_panic("__fortify_strlen");
JUMPOUT(0x2EFLL);
}
```
### spy_exit
```c
void __cdecl spy_exit()
{
unregister_keyboard_notifier(&spy_blk);
debugfs_remove(subdir);
printk(&unk_E48);
}
```
### logs
```txt
ujin}zu|xkp}nqvxtpz}96vimujz}96kvvm6uj94ux|zqv9FKJQP_MFFKJQP_MFFKJQP_MF;FUJQP_MFFUJQP_MFFUJQP_MFFUJQP_MFQFUJQP_MFPFKJQP_MF;9FKJQP_MFFKJQP_MFFKJQP_MF'9q|`7mamzxm9q|`7mamz}96qvt|6ujz}9qm{ujz}9FUJQP_MF]|jrmviuj|zqv9FKJQP_MF;`vv9jli9{vppppFKJQP_MF;9FKJQP_MF'9q|uuv7mamzxm9q|uuv7mamz}96kvvm6x}xtwxwv9ixjj7mamx}xt9FKJQP_MFFKJQP_MFFKJQP_MFFKJQP_MFFKJQP_MF#9FKJQP_MFFKJQP_MFFKJQP_MFFKJQP_MFFKJQP_MFFKJQP_MFFKJQP_MF;jli|kj*zlk*ixjjn)k}FKJQP_MF;FUZMKUFFUZMKUFa`zu|xk{`|9{`|7
```
1. Nama Authornya adalah `0xEr3n`, dapat dilihat di strings Kernel Modulenya

2. Fungsi yang ngeregister keyboard eventsnya adalah `register_keyboard_notifier`
```c
int __cdecl spy_init()
{
dentry *dir; // rax
_fentry__();
LODWORD(dir) = -22;
if ( (unsigned int)codes <= 2 )
{
dir = (dentry *)debugfs_create_dir("spyyy", 0LL);
subdir = dir;
if ( (unsigned __int64)dir <= 0xFFFFFFFFFFFFF000LL )
{
if ( dir )
{
if ( debugfs_create_file("keys", 256LL, dir, 0LL, &keys_fops) )
{
register_keyboard_notifier(&spy_blk); // <-- ini
//// ... ///
```
3. Fungsi yang ngeconvert keycodes ke strings adalah fungsi `keycode_to_string`
```c
void __fastcall keycode_to_string(__int64 keycode, __int64 shift_mask, char *buf, __int64 type)
{
char *v4; // rdx
int v5; // ecx
__int64 v6; // rdi
const char *v7; // rcx
_fentry__(keycode, shift_mask, buf, type);
if ( v5 == 1 )
{
if ( (unsigned int)(keycode - 1) <= 0x2FD )
snprintf(v4, 0xCuLL, "%x %x", keycode, shift_mask);
}
else if ( v5 == 2 )
{
if ( (unsigned int)(keycode - 1) <= 0x2FD )
snprintf(v4, 0xCuLL, "%d %d", keycode, shift_mask);
}
else if ( !v5 && (unsigned int)(keycode - 1) <= 0x76 )
{
v6 = (int)keycode;
if ( (_DWORD)shift_mask == 1 )
v7 = us_keymap[v6][1];
else
v7 = us_keymap[v6][0];
snprintf(v4, 0xCuLL, "%s", v7);
}
}
```
4. Perhatikan fungsi `spy_init`
```c
int __cdecl spy_init()
{
/// --- ///
dir = (dentry *)debugfs_create_dir("spyyy", 0LL);
/// --- ///
if ( debugfs_create_file("keys", 256LL, dir, 0LL, &keys_fops) )
/// --- ///
```
By default, debugfs dimount di `/sys/kernel/debug` jadi path file yang dicreate `brainstorm.ko` untuk ngestore logs berada di `/sys/kernel/debug/spyyy/keys`
5. Perhatikan ketika `brainstorm.ko` diinitialized, yakni pada fungsi `spy_init`
```c
int __cdecl spy_init()
{
/// --- ///
printk(&unk_C11);
/// --- ///
```
Fungsi `printk` digunakan untuk ngeprint text di `kernel log buffer` (ring buffer yang diexport ke `userspace` melalui `/dev/kmsg`) (https://docs.kernel.org/core-api/printk-basics.html). Saya cek string dereferencenya dengan `radare2`


Karena `printk(&unk_C11)` hanya menggunakan satu parameter dalam calling conventionnya, jadi register yang digunakan untuk `&unk_C11` adalah `Destination Index Register (RDI)`
```asm
0x08000340 48c7c7000000. mov rdi, 0 ; RELOC 32 .rodata.str1.1 @ 0x08000ca6 + 0xb
0x08000347 e800000000 call _printk ; RELOC 32 _printk
```
Langsung cek string dereference dari `0x08000ca6 + 0xb` karena address tersebut merupakan location dari `&unk_C11`

Jadi, string yang ditampilkan dilayar setelah `brainstorm.ko` diimport adalah `w00tw00t`
6. Xor keynya adalah 0x19
```c
// bad sp value at call has been detected, the output may be wrong!
__int64 spy_cb()
/// --- ///
if ( v2 > 0xC )
spy_cb_cold(buf, 12LL, v2);
if ( v2 == 12 )
JUMPOUT(0x2E3LL);
if ( v2 )
{
v4 = buf;
v5 = &buf[v2];
do
*v4++ ^= 0x19u; // <- ini xor_keynya
while ( v5 != v4 );
v6 = buf_pos + v3;
v7 = &keys_buf[buf_pos];
/// --- ///
```
7. Langsung saja xor logsnya dengan xor_key (0x19) untuk mendecrypt logsnya
```python
#!/usr/bin/env python3
pt = ''
logs = open('logs', 'rb').read()
for x in logs:
pt += chr(x ^ 0x19)
print(pt)
```

### decrypted logs
```txt
ls
pwd
clear
id
whoami
cd /opt
ls
cd /root/
ls -la
echo _RSHIFT__RSHIFT__RSHIFT_"_LSHIFT__LSHIFT__LSHIFT__LSHIFT_H_LSHIFT_I_RSHIFT_" _RSHIFT__RSHIFT__RSHIFT_> hey.txt
cat hey.txt
cd /home/
ls
cd htb
ls
cd _LSHIFT_Desktop
ls
echo _RSHIFT_"yoo sup boiiii_RSHIFT_" _RSHIFT_> hello.txt
cat hello.txt
cd /root/adam
nano pass.txt
adam _RSHIFT__RSHIFT__RSHIFT__RSHIFT__RSHIFT_: _RSHIFT__RSHIFT__RSHIFT__RSHIFT__RSHIFT__RSHIFT__RSHIFT_"supers3cur3passw0rd_RSHIFT_"_LCTRL__LCTRL_xy
clear
bye bye.
```
Dapat dilihat bahwa adam mengcreate password dengan `nano.txt` kemudian memasukan `supers3cur3passw0rd`. Jadi, passwordnya adalah `supers3cur3passw0rd`