<h1 id="Hack-The-Box">Hack The Box - Reversing (Easy Part 4)</h1>

Ghi chú:
<ul>
<li>Easy: 22-28 challenge</li>
<ul>
<li><a href="#RAuth ">22. RAuth </a></li>
<li><a href="#Partial Encryption">23. Baby Crypt </a></li>
<li><a href="#Golfer - Part 1 ">24. Golfer - Part 1</a></li>
<li><a href="#Up a Stream ">25. Up a Stream </a></li>
<li><a href="#Spooky License">26. Spooky License</a></li>
<li><a href="#Encryption Bot ">27. Encryption Bot </a></li>
<li><a href="#Cyberpsychosis ">28. Cyberpsychosis </a></li>
<li><a href="#ARMs Race ">29. ARMs Race </a></li>
</ul>
</li>
</ul>
<h2>Difficulty: Easy </h2>
<div id="RAuth"></div>
<h3>Challenge 22: RAuth</h3>
My implementation of authentication mechanisms in C turned out to be failures. But my implementation in Rust is unbreakable. Can you retrieve my password?
<a href="https://drive.google.com/file/d/1eDq_Iwg8HTI2G01OPMgC-oudBSi3OKlN/view?usp=sharing">Download Challenge Here</a>
<h3>Solution</h3>
Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

Mở chương trình trong IDA.
Thoạt đầu quan sát, chương trình yêu cầu đầu vào là một chuỗi. Sau một vài lần gỡ lỗi, tôi nhận ra rằng chúng tôi cần vá tại `0x690D từ jz sang jnz` và chúng tôi đã nhận được:

Không thể dễ thế! Dành nhiều thời gian hơn để đọc, tôi nhận thấy nó truy cập vào “salsa20” rất nhiều lần. Sau khi tìm kiếm, chúng tôi nhận được nhiều thông tin chi tiết về <a href=https://en.wikipedia.org/wiki/Salsa20>Salsa20</a>.

Trạng thái ban đầu của Salsa20 được tạo thành từ mười sáu từ 32 bit được sắp xếp dưới dạng ma trận 4×4 bằng cách sử dụng `key` và `nonce`. Chúng ta cần tìm 2 tham số. Ta có trạng thái ban đầu của Salsa20, nó sử dụng:
* `ef39f4f20e76e33bd25f4db338e81b10` là `key` (xmmword_39CA0 + xmmword_39CB0)
* `d4c270a3` là `nonce`
* `05055FB1A329A8D558D9F556A6CB31F324432A31C99DEC72E33EB66F62AD1BF9` là `cipher` (xmmword_39CC0 + xmmword_39CD0)
* `193978899768A08F66D39017B2E040C237193763C581E261` là `fake_flag`
Chúng ta rút gọn ma trận: `expa`ef39f4f20e76e33b`nd 3`d4c270a3 `2-by`d25f4db338e81b10`te k`
:::info
```
65787061 65663339 66346632 30653736
65333362 6E642033 64346332 37306133
00000000 00000000 322D6279 64323566
34646233 33386538 31623130 7465206B
```
:::

Phần còn lại là giải mã Salsa, bạn có thể đọc nếu muốn. Cách chương trình in mật khẩu giống như cách in cờ. Bây giờ chúng ta viết mã để giải quyết phần còn lại.
:::info
```python
from Crypto.Cipher import Salsa20
key = b"ef39f4f20e76e33bd25f4db338e81b10"
nonce = b"d4c270a3"
# Password: TheCrucialRustEngineering@2021;)
cipher = Salsa20.new(key=key, nonce=nonce)
data = (bytes.fromhex("05055FB1A329A8D558D9F556A6CB31F324432A31C99DEC72E33EB66F62AD1BF9"))
password = cipher.decrypt(data)
print(password)
# Fake flag: HTB{F4k3_f74g_4_t3s7ing}
cipher = Salsa20.new(key=key, nonce=nonce)
data = ((bytes.fromhex("193978899768A08F66D39017B2E040C237193763C581E261")))
fakeflag = cipher.decrypt(data)
print(fakeflag)
```
:::
Bây giờ chúng ta có thể bắt đầu làm việc trên dịch vụ từ xa.

:::success
```
Flag: HTB{I_Kn0w_h0w_t0_5al54}
```
:::
<div id="Partial Encryption"></div>
<h3>Challenge 23: Partial Encryption</h3>
Static-Analysis on this program didn't reveal much. There must be a better way to approach this...
<a href="https://drive.google.com/file/d/1y5qXCV19u2ZRsU_YUcRZ0GQ4X3boSsNC/view?usp=drive_link">Download Challenge Here</a>
<h3>Solution</h3>
Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

Mở chương trình trong IDA. Tôi chỉ biết `sub_7FF775DF1050` với tham số giải mã để lấy hàm được giải mã nhưng tôi không biết thuật toán. Nếu ai có hình có thể bình luận bên dưới.





:::success
```
Flag: HTB{W3iRd_RUnT1m3_DEC}
```
:::
<div id="Golfer - Part 1"></div>
<h3>Challenge 24: Golfer - Part 1</h3>
A friend gave you an odd executable file, in fact it is very tiny for a simple ELF, what secret can this file hide?
<a href="https://drive.google.com/file/d/18D71AKKpLOcbdH9pVjss98BL5N91FR-_/view?usp=drive_link">Download Challenge Here</a>
<h3>Solution</h3>
Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

Mở chương trình trong IDA.
:::info
```asm!
0800004C public start
0800004C start
0800004C jmp start_0
08000051 ; ---------------------------------------------------------------------------
08000051 inc bl
08000053 inc dl
08000055 mov ecx, 800000Ah
0800005A call loc_800012F
0800005F mov ecx, offset byte_8000008
08000064 call loc_800012F
08000069 mov ecx, offset dword_8000024
0800006E call loc_800012F
08000073 mov ecx, 800000Eh
08000078 call loc_800012F
0800007D mov ecx, 800000Ch
08000082 call loc_800012F
08000087 mov ecx, 8000023h
0800008C call loc_800012F
08000091 mov ecx, offset byte_8000009
08000096 call loc_800012F
0800009B mov ecx, 8000021h
080000A0 call loc_800012F
080000A5 mov ecx, offset byte_8000006
080000AA call loc_800012F
080000AF mov ecx, 800000Dh
080000B4 call loc_800012F
080000B9 mov ecx, 8000022h
080000BE call loc_800012F
080000C3 mov ecx, 8000021h
080000C8 call loc_800012F
080000CD mov ecx, offset byte_8000005
080000D2 call loc_800012F
080000D7 mov ecx, 8000021h
080000DC call loc_800012F
080000E1 mov ecx, offset dword_8000020
080000E6 call loc_800012F
080000EB mov ecx, 8000023h
080000F0 call loc_800012F
080000F5 mov ecx, 800000Fh
080000FA call loc_800012F
080000FF mov ecx, offset byte_8000007
08000104 call loc_800012F
08000109 mov ecx, 8000022h
0800010E call loc_800012F
08000113 mov ecx, 8000025h
08000118 call loc_800012F
0800011D mov ecx, 800000Bh
08000122 call loc_800012F
08000127
08000127 start_0 proc near
08000127 xor al, al
08000129 inc al
0800012B mov bl, 2Ah ; '*'
0800012D int 80h
0800012F
0800012F loc_800012F
0800012F
0800012F push ebp
08000130 mov ebp, esp
08000132 mov al, 4
08000134 int 80h
08000136 leave
08000137 retn
08000137 start_0 endp
```
:::
Sau khi tìm kiếm về NASM, tôi tìm thấy một số thông tin hữu ích

Chương trình cố gắng gọi `sys_exit`. Ta có thể bỏ qua nó và đọc đoạn trên, nó sẽ gọi `sys_write` với kí tự của `flag` được đưa vào `ecx`


:::success
```
Flag: HTB{y0U_4R3_a_g0lf3r}
```
:::
<div id="Up a Stream"></div>
<h3>Challenge 25: Up a Stream</h3>
Java streams are great! Why use 10 lines of completely readable code, when you could mash it all into 67 characters? +1, PR Approved!
<a href="https://drive.google.com/file/d/1agpWWXzEizytiiWxGfI2XNfDoKmDGiI0/view?usp=sharing">Download Challenge Here</a>
<h3>Solution</h3>
Ta nhận được tệp `stream.jar` và `ouput.txt`. Tôi giải nén `stream.jar` và nhận được `Challenge.class`. Sử dụng https://www.decompiler.com/ để mở `Challenge.class`, ta nhận được tệp `Challenge.java`.
:::info
```javascript
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Challenge {
public static void main(String[] var0) {
String var1 = "FLAG";
Stream var10000 = dunkTheFlag(var1).stream();
PrintStream var10001 = System.out;
Objects.requireNonNull(var10001);
var10000.forEach(var10001::println);
}
private static List<String> dunkTheFlag(String var0) {
return Arrays.asList(((String)((List)((String)((List)((String)((List)var0.chars().mapToObj((var0x) -> {
return (char)var0x;
}).collect(Collectors.toList())).stream().peek((var0x) -> {
hydrate(var0x);
}).map((var0x) -> {
return var0x.toString();
}).reduce("", (var0x, var1) -> {
return var1 + var0x;
})).chars().mapToObj((var0x) -> {
return (char)var0x;
}).collect(Collectors.toList())).stream().map((var0x) -> {
return var0x.toString();
}).reduce(String::concat).get()).chars().mapToObj((var0x) -> {
return var0x;
}).collect(Collectors.toList())).stream().map((var0x) -> {
return moisten(var0x);
}).map((var0x) -> {
return var0x;
}).map(Challenge::drench).peek(Challenge::waterlog).map(Challenge::dilute).map(Integer::toHexString).reduce("", (var0x, var1) -> {
return var0x + var1 + "O";
})).repeat(5));
}
private static Integer hydrate(Character var0) {
return var0 - 1;
}
private static Integer moisten(int var0) {
return (int)(var0 % 2 == 0 ? (double)var0 : Math.pow((double)var0, 2.0D));
}
private static Integer drench(Integer var0) {
return var0 << 1;
}
private static Integer dilute(Integer var0) {
return var0 / 2 + var0;
}
private static byte waterlog(Integer var0) {
var0 = ((var0 + 2) * 4 % 87 ^ 3) == 17362 ? var0 * 2 : var0 / 2;
return var0.byteValue();
}
}
```
:::
Đoạn mã mô tả:
* `hydrate`: Giảm giá trị ASCII của mỗi ký tự đi 1.
* `moisten`: Nếu số là chẵn, giữ nguyên giá trị, ngược lại, làm bình phương giá trị.
* `drench`: Dịch trái số nguyên một bit.
* `dilute`: Chia giá trị cho 2 và cộng lại với giá trị ban đầu.
* `waterlog`: Thực hiện một phép toán phức tạp trên giá trị, sau đó chuyển đổi thành số byte. Nếu một điều kiện được đáp ứng, giá trị được nhân đôi; ngược lại, giá trị được chia cho 2.
Bản thân tôi rất ít khi làm các đề `java`. Tôi đã tìm hiểu các `Stream API` để hiểu rõ hoạt động:
* `Stream reduction operation` cho phép chúng ta tạo ra một kết quả duy nhất từ các phần tử của Stream bằng cách áp dụng các phép tính lặp đi lặp lại trên các phần tử của nó. <a href="https://shareprogramming.net/huong-dan-su-dung-stream-reduce/"> Đọc thêm tại đây. </a>
* `Stream peek()` là một phương thức được sử dụng để thực hiện hành động trên mỗi phần tử của một luồng mà không làm thay đổi luồng đó. <a href="https://shareprogramming.net/su-dung-stream-peek-sao-cho-dung-cach/"> Đọc thêm tại đây. </a>
Ta phân tích luồng chương trình như sau:
1. Chuyển đổi `Flag` thành một luồng các ký tự trong chuỗi.
2. Gom các kí tự đó thành một `List`.
3. Thực hiện phương thức `hydrate()` trên mỗi ký tự trong danh sách, giảm giá trị Unicode của ký tự đi một đơn vị. Tuy nhiên nó dùng trong phương thức`peek` => giá trị không đổi.
4. Chuyển các kí tự thành chuỗi rồi gộp lại thành một chuỗi `ĐÃ ĐƯỢC ĐẢO NGƯỢC`. Vì họ dùng `reduce("", (var0x, var1) -> { return var1 + var0x; }`. Ta có ví dụ như sau: `flag=HTB{minhkingkong} => '}gnokgnikhnim{BTH'`
5. Tiếp tục chuyển chuỗi đã bị đảo ngược thành danh sách các kí tự và chuyển thành giá trị nguyên. Lưu các giá trị đó vào một danh sách mới và ép kiểu các giá trị trong đó thành `int`.
6. Thực hiện phương thức `moisten(), drench(), waterlog(), dilute()` để mã hóa danh sách trên. Tuy nhiên phương thức `waterlog()` dùng trong phương thức`peek` => giá trị không đổi.
7. Chuyển đổi mỗi giá trị int thành một chuỗi thập lục phân. Nối các chuỗi thập lục phân thành một chuỗi duy nhất.
8. Lặp lại như trên năm lần và trả kết quả để in.
Ta biết chuỗi đầu ra được lặp lại 5 lần, từ đó ta trích được chuỗi: `b71bO12cO156O6e43Od8O69c3O5cd3O144Oe4O6e43O37cbOf6O69c3O1e7bO156O3183O69c3O6cO8b3bOc0O1e7bO156OfcO50bbO69c3Oc0O102O6e43OdeOb14bOc6OfcOd8O`
Từ đây tôi viết chương trình để tìm ra `flag`
:::info
```python
data = [0xb71b, 0x12c, 0x156, 0x6e43, 0xd8, 0x69c3, 0x5cd3, 0x144, 0xe4, 0x6e43, 0x37cb, 0xf6, 0x69c3, 0x1e7b, 0x156, 0x3183, 0x69c3, 0x6c, 0x8b3b, 0xc0, 0x1e7b, 0x156, 0xfc, 0x50bb, 0x69c3, 0xc0, 0x102, 0x6e43, 0xde, 0xb14b, 0xc6, 0xfc, 0xd8]
flag = ""
for i in range(len(data) - 1, -1, -1):
# dilute
value = int(data[i] / 1.5)
# drench
value >>= 1
# moisten
if value % 2 != 0:
value = int(value ** 0.5)
flag += chr(value)
print(flag)
```
:::
Bạn có thể đọc đoạn mã ở dưới để hiểu được luồng của chương trình.
:::info
```javascript
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Challenge {
public static void main(String[] arrstring) {
String string = "HTB{JaV@_STr3@m$_Ar3_REaLlY_Hard}";
Challenge.dunkTheFlag(string).stream().forEach(System.out::println);
}
private static List<String> dunkTheFlag(String string3) {
return Arrays.asList(string3.chars().mapToObj(n -> Character.valueOf((char)n)).collect(Collectors.toList()).stream().peek(c -> Challenge.hydrate(c)).map(c -> c.toString()).reduce("", (string, string2) -> string2 + string).chars().mapToObj(n -> Character.valueOf((char)n)).collect(Collectors.toList()).stream().map(c -> c.toString()).reduce(String::concat).get().chars().mapToObj(n -> n).collect(Collectors.toList()).stream().map(n -> Challenge.moisten(n)).map(n -> (int)n).map(Challenge::drench).peek(Challenge::waterlog).map(Challenge::dilute).map(Integer::toHexString).reduce("", (string, string2) -> string + string2 + "O").repeat(5));
}
private static Integer hydrate(Character c) {
return c.charValue() - '\u0001';
}
private static Integer moisten(int n) {
return (int)(n % 2 == 0 ? (double)n : Math.pow(n, 2.0));
}
private static Integer drench(Integer n) {
return n << 1;
}
private static Integer dilute(Integer n) {
return n / 2 + n;
}
private static byte waterlog(Integer n) {
n = ((n + 2) * 4 % 87 ^ 3) == 17362 ? n * 2 : n / 2;
return n.byteValue();
}
}
```
:::
:::success
```
Flag: HTB{JaV@_STr3@m$_Ar3_REaLlY_Hard}
```
:::
<div id="Spooky License"></div>
<h3>Challenge 26: Spooky License</h3>
After cleaning up we found this old program and wanted to see what it does, but we can't find the licence we had for it anywhere. Can you help?
<a href="https://drive.google.com/file/d/1WjV1d6DH8oihQuPhjqN4-exDy7HkTnQ1/view?usp=sharing">Download Challenge Here</a>
<h3>Solution</h3>
Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

Mở chương trình trong IDA.

Bạn có thể sử dụng z3 hoặc angr, tùy bạn. Nhưng tôi đề cập đến việc sử dụng angr với việc thực hiện điều kiện challange, z3 khi phép tính không kéo dài.
:::info
```python
import angr
import claripy
import sys
def main(argv):
path_to_binary = "spookylicence"
proj = angr.Project(path_to_binary, load_options={'auto_load_libs':False})
sym_arg_size = 32
sym_arg=claripy.BVS('sym_arg', 8*sym_arg_size)
argv.append(sym_arg)
initial_state = proj.factory.entry_state(args=argv,add_options={angr.sim_options.ZERO_FILL_UNCONSTRAINED_REGISTERS,angr.sim_options.ZERO_FILL_UNCONSTRAINED_MEMORY})
simulation = proj.factory.simulation_manager(initial_state )
exit_address = 0x400000+0x187d
avoid_address = 0x400000+0x1890
simulation.explore(find=exit_address, avoid=avoid_address)
if simulation.found:
solution = simulation.found[0].solver.eval(argv[1], cast_to=bytes)
print(solution)
else:
print("Failed")
if __name__ == '__main__':
main(sys.argv)
```
:::
:::success
```
Flag: HTB{The_sp0000000key_liC3nC3K3Y}
```
:::
<div id="Encryption Bot"></div>
<h3>Challenge 27: Encryption Bot</h3>
My friend send me a encrypted message by using encryption bot. This is a important message. Can you decrypt the message for me?
<a href="https://drive.google.com/file/d/1IRUSEA6HDhQ1SPCsxTqmyDGEtwKYj60O/view?usp=sharing">Download Challenge Here</a>
<h3>Solution</h3>
Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

Mở chương trình trong IDA.

Chương trình kiểm tra độ dài dữ liệu ta nhập vào có là 27, sau đó chuyển nó thành hệ nhị phân.

Mục đích chuyển thành hệ nhị phân để bắc cầu - chuyển đổi dữ liệu theo hệ 6. Kết quả đó sẽ được chuyển thành hệ thập phân và lấy kí tự ASCII.

:::info
```python
data = "RSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQabcdefghijklmnopqrstuvwxyz"
flag_encrypt = "9W8TLp4k7t0vJW7n3VvMCpWq9WzT3C8pZ9Wz"
index = [data.index(char) for char in flag_encrypt if char in data]
binary = ''.join(format(num, '06b') for num in index)
binary_chunks = [binary[i:i+8] for i in range(0, len(binary), 8)]
flag = ''.join([chr(int(chunk, 2)) for chunk in binary_chunks])
print(flag)
```
:::
:::success
```
Flag: HTB{3nCrypT10N_W1tH_B1Ts!!}
```
:::
<div id="Cyberpsychosis"></div>
<h3>Challenge 28: Cyberpsychosis</h3>
Malicious actors have infiltrated our systems and we believe they've implanted a custom rootkit. Can you disarm the rootkit and find the hidden data?
<a href="https://drive.google.com/file/d/1Ry4GSQ1vHbt_oePl1CTQwtwLYT-NlmIT/view?usp=sharing">Download Challenge Here</a>
<h3>Solution</h3>
Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

>Loadable kernel modules (. ko files) là một phần mở rộng tệp quan trọng trong hệ điều hành Linux. Nó cho phép người dùng và nhà phát triển mở rộng khả năng của nhân Linux và tùy chỉnh hệ thống của họ theo nhu cầu cụ thể.
>Tệp .ko là một tệp đối tượng đã được biên dịch chứa mã được thiết kế đặc biệt để hoạt động với nhân Linux. Tệp này có thể chứa mã cho các tính năng hoặc chức năng mới, chẳng hạn như trình điều khiển thiết bị, mô-đun hệ thống tệp hoặc mô-đun bảo mật.
Mở chương trình trong IDA.

Trong lập trình và bảo mật hệ thống, `_fentry__` là một hàm liên quan đến Linux Kernel, nó là nơi mà một hàm sẽ nhảy đến ngay sau khi được gọi, trước khi bất kỳ mã chính nào của hàm đó được thực thi. Đây là một phần của cơ chế ftrace, một công cụ trong hạt nhân Linux được sử dụng để debug và theo dõi hệ thống.
Ngay từ đầu, tôi xác định rằng nó có thể liên quan đến rootkit hoặc một số dạng phần mềm độc hại có thể thay đổi bảng lệnh gọi hệ thống để ẩn mô-đun khỏi một số kiểm tra nhất định.
Ta cần hiểu luồng tư duy như sau: rootkit cần đánh lừa người dùng ở chế độ người dùng, tức là thực hiện kiểm soát giao diện giữa User-mode và Kernel-mode. Một trong số đó có kỹ thuật hooking: chuyển hướng một cuộc gọi hệ thống đến một chức năng tùy chỉnh.
Đầu tiên nó sẽ tìm `syscall table`, sau đó là thay thế các cuộc gọi hệ thống bằng các hàm của kẻ tấn công. Trong thực tế, chỉ cần sửa `syscall table` - nơi chứa địa chỉ của các lệnh gọi hệ thống.

Hàm `get_syscall_table_bf():` Hàm này dùng để lấy địa chỉ của bảng syscall.

`module_hide():` Chức năng này dường như được thiết kế để ẩn mô-đun khỏi danh sách mô-đun hạt nhân Linux. Theo <a href="https://stackoverflow.com/questions/61073163/what-does-the-linux-page-address-0xdead0000-mean">link </a> để hiểu thêm
* Khai báo biến `prev` và `next` trỏ đến cấu trúc `list_head`, đại diện cho một nút trong danh sách liên kết.
* Thực hiện loại bỏ mô-đun hiện tại khỏi danh sách.
* Gán địa chỉ không hợp lệ cho con trỏ nút tiếp theo của mô-đun hiện tại.
* Đặt cờ toàn cục `module_hidden` để chỉ ra mô-đun bị ẩn.

Chương trình thực hiện lấy địa chỉ của 3 hàm `getdents` `getdents64` `kill` và thay thế địa chỉ đó bằng các hàm custom.
Đoạn mã khá dài nên mình không upload đoạn mã lên mà tiến hành mô tả từng hàm custom:
1. `hacked_getdents và hacked_getdents64` - Hàm này thay đổi hành vi của hàm getdents. Nó cấp phát bộ nhớ cho một biến v5 và kiểm tra vùng nhớ vừa được cấp. Sau đó, sao chép dữ liệu từ User-space và Kernel-space. Xử lý dữ liệu trả về từ hàm gốc getdents. Cuối cùng, hàm này giải phóng bộ nhớ được cấp phát và trả về kích thước của dữ liệu đã được xử lý. Đọc tại đây để biết thêm chi tiết kĩ thuật https://github.com/m0nad/Diamorphine/blob/master

Là một rootkit, tôi tìm <a href="https://github.com/m0nad/Diamorphine">rootkit source</a>. Ta cần cũng tìm thấy một số lệnh để vô hiệu hóa rootkit. Tôi nhận ra rằng mục tiêu của chúng tôi là hiển thị tệp máy chủ để chúng tôi có thể nhận được cờ.

2. `hacked_kill()` - cho phép ta tắt tính năng "hidden" các module
* `Quá trình đầu tiên:` "kill -46 0" thao tác này sẽ "tắt khả năng tàn hình" rootkit khiến nó hiển thị. <a href="https://stackoverflow.com/questions/61073163/what-does-the-linux-page-address-0xdead0000-mean">Đọc để hiểu thêm.</a>
* `Quy trình thứ hai:` `kill -64 0` nó sửa đổi thông tin xác thực kernel bằng cách sử dụng các hàm `prepare_creds` và `commit_creds`, đặt một số trường nhất định thành 0. Lưu ý rằng việc sử dụng `struct cred` để đặt giá trị UID và GID thành 0 <b>không đảm bảo tiến trình</b> sẽ trở thành root. Nếu các giá trị khác như EUID, SUID, FSUID cũng không được đặt thành 0 thì quyền truy cập có thể vẫn khác với quyền root.
* `Quy trình thứ ba:` `kill -31 0` bỏ ẩn bất kỳ tiến trình nào, `kill -<num> 0` đang thực hiện `orig_kil()`
Lệnh `lsmod` được sử dụng để hiển thị danh sách các mô-đun hạt nhân đang được tải trong hệ thống.
Ta thực hiện `rmmod diamorphine` vì trạng thái các module trong Linux Kernel vẫn `diamorphine`, chúng ta phải gỡ bỏ nó và hiển thị tất cả các file. Từ đó ta truy cập hệ thống với người dùng đang đăng nhập là `root`

:::success
```
Flag: HTB{N0w_Y0u_C4n_S33_m3_4nd_th3_r00tk1t_h4s_b33n_sUcc3ssfully_d3f34t3d!!}
```
:::
<div id="ARMs Race"></div>
<h3>Challenge 29: ARMs Race</h3>
The famous hacker Script K. Iddie has finally been caught after many years of cybercrime. Before he was caught, he released a server sending mysterious data, and promised his 0-days to anyone who could solve his multi-level hacking challenge. Now everyone is in an ARMs race to get his exploits. Can you be the one to solve Iddie's puzzle?
<a href="https://drive.google.com/file/d/1qF2NiXcn6vhF2Y2sNGLdk6Q4Jfpurffa/view?usp=sharing">Download Challenge Here</a>
<h3>Solution</h3>
Khi kết nối Instance, ta được truy cập đến trang web với nội dung là mã Hex.

Ta đang ở Level 1/50, ta có thể dự đoán rằng khi ta vượt qua 50 level thì ta nhận được flag. Ngoài ra, chuỗi hexa ta cung cấp có thể tạo thành các câu lệnh của ARM. Nó yêu cầu ta tính toán thanh ghi R0 của các câu lệnh ARM ấy. Ta sẽ cần sử dụng `socket` để kết nối đến địa chỉ được cấp, cũng như gửi kết quả tính được của thanh ghi R0. Các trường hợp khi ta kết nối:
* `Timeout! You took too long to provide input.` - khi kết quả gửi chậm.
* `Value not recognized` - khi kết quả gửi không phải là hex.
* `Wrong answer` - khi kết quả gửi không đúng.
* `Level */50:` - kết quả đúng và qua level kế tiếp.
Ta viết chương trình để kết nối đến địa chỉ IP được cấp và thực hiện tính toán. Lưu ý:
* `mov`, `movw`, `movt` được sử dụng không có quy luật.
* Cờ `CF` không có gây ảnh hưởng đến các phép tính có dấu.
:::info
```c
import socket
from capstone import *
def recvuntil(sock, delim=b'\n'):
data = b''
while not data.endswith(delim):
data += sock.recv(1)
return data
def HexToArm(data):
data = data.upper()
csarmv7 = Cs(CS_ARCH_ARM, CS_MODE_ARM)
csarmv7.detail = True
disassembly = []
for insn in csarmv7.disasm(bytes.fromhex(data), 0):
disassembly.append(f"{insn.mnemonic} {insn.op_str}")
R0, R1, R2 = 0, 0, 0
for line in disassembly:
if "mov" in line:
value = int(line.split("#")[1].strip(), 16)
if "r0" in line:
R0 = value
elif "r1" in line:
R1 = value if "movw" in line or "mov " in line else (R1 + (value << 16))
elif "r2" in line:
R2 = value if "movw" in line or "mov " in line else (R2 + (value << 16))
if any(op in line for op in ["r0, r0, #0", "r0, r0, r1"]):
action = line.split()[0]
if action == "add":
R0 += R1 + R2
elif action == "sub":
R0 = (R0 - R1 - R2) + 0xFFFFFFFF
elif action == "and":
R0 &= R1 & R2
elif action == "eor":
R0 ^= R1 ^ R2
elif action == "mul":
R0 *= R1 * R2
elif action == "orr":
R0 |= R1 | R2
elif action == "rsb":
R0 = 0x100000000 - R0
return hex(R0 & 0xFFFFFFFF)
def main():
host = "IP"
port =
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
for i in range(50):
response = recvuntil(sock)
decoded_response = response.decode()
print(decoded_response)
if "Wrong answer" in decoded_response or i == 50:
sock.close()
break
colon_index = decoded_response.find(': ')
content = decoded_response[colon_index + 1:].strip()
response = recvuntil(sock, b'Register r0:')
decoded_response = response.decode()
result = HexToArm(content)
sock.send((result + '\n').encode())
print(decoded_response+result+"\n")
sock.close()
if __name__ == "__main__":
main()
```
:::
Phiên bản tốt hơn của đoạn mã
:::info
```python
import socket
from unicorn import *
from unicorn.arm_const import *
def recvuntil(sock, delim=b'\n'):
data = b''
while not data.endswith(delim):
data += sock.recv(1)
return data
def HexToArm(hex_str):
code_bytes = bytes.fromhex(hex_str)
# Initialize Unicorn for ARM architecture
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
# Map 2MB memory for this emulation at address 0x10000
ADDRESS = 0x10000
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# Write machine code to be emulated to memory
mu.mem_write(ADDRESS, code_bytes)
mu.reg_write(UC_ARM_REG_R0, 0x0)
# Emulate machine code in infinite time
try:
mu.emu_start(ADDRESS, ADDRESS + len(code_bytes))
except UcError as e:
print("ERROR: %s" % e)
# Read back the value of R0 register
r0 = mu.reg_read(UC_ARM_REG_R0)
return str(r0)
def main():
host = "IP"
port =
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
for i in range(51):
response = recvuntil(sock)
decoded_response = response.decode()
print(decoded_response)
colon_index = decoded_response.find(': ')
content = decoded_response[colon_index + 1:].strip()
response = recvuntil(sock, b'Register r0:')
decoded_response = response.decode()
result = HexToArm(content)
sock.send((result + '\n').encode())
print(decoded_response+result+"\n")
sock.close()
if __name__ == "__main__":
main()
```
:::