KnightCTF 2023

KnightCTF 2023


Nguồn ở đây nhá các bạn: 💀👆👆👆💀

Xin chào năm mới mọi người, Team tôi khai xuân năm mới với một giải nhẹ nhàng. Một giải server máy chủ gặp trục trặc nhiều quá…. Nhưng không sao nhiều bài cũng ổn đối với mình, nó cũng nhiều bài làm đa dạng sau một thời gian tôi ngủ đông. Đơn giản thui thui bắt đầu luôn nhé…👻

1: KrackMe 1.0 (Solved)

title

Vâng bài đầu tiên nhé. Như thường lệ mình sẽ kiểm tra kiểu file bằng HxD, CFF Explorer… để check cái thứ cần thiết nhé và sau đó chạy IDA pro và phần mình quan tâm đây là:

Một số kiến thức phổ cập trước khi vào bài nhá:

  • Arguments to main:(link)

      int main( void )
      int main( int argc, char *argv[] )
      int main( int argc, char *argv[], char *envp[] )
    
  • Hàm main cũng như các hàm khác có nghĩa là đều nhận đối số để xử lí. Tuy nhiên tham số trong hàm main đã dc C định nghĩa sẵn, và có thứ tự:
    • int agrc: đối số cho biết tham số đã nhập, kể cả tên chương trình.
    • char *argv[] hoặc char **argv: mảng các pointer trỏ đến các chuỗi là tham số đi theo sau tên chương trình khi chạy chương trình từ DOS. Chuỗi là tên chương trình luôn được chỉ bởi argv[0].
    • char *envp[], is an array of pointers to environment variables (là một mảng các trỏ tới các môi trường). Mảng này được kết thúc bởi một con trỏ null (a null pointer).
  • Nếu một chương trình được gọi nà không có đối số dòng lệnh sẽ nhận giá trị 1 cho argc, vì tên tệp của tệp thực thi được đặt trong argv[0]. Các chuỗi được trỏ bởi argv[1] đến argv[argc-1] đại diện tham số chương trình.

  • Các tham số argcargv có thể sửa đổi được và giữ lại các giá trị được lưu trữ lần cuối giữa khởi động chương trình và kết thúc chương trình.

  • HIBYTE() func - là hàm để lưu trữ byte bậc cao (high-order byte).

      // phần định nghĩa HIBYTE trong C
      #define HIBYTE(w) ((char)(((__int16)(w) >> 8) & 0xFF))
    
int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int i; // [rsp+10h] [rbp-170h]
  unsigned int j; // [rsp+10h] [rbp-170h]
  unsigned int k; // [rsp+10h] [rbp-170h]
  unsigned int m; // [rsp+10h] [rbp-170h]
  unsigned int n; // [rsp+10h] [rbp-170h]
  int ii; // [rsp+10h] [rbp-170h]
  int jj; // [rsp+10h] [rbp-170h]
  unsigned int kk; // [rsp+10h] [rbp-170h]
  int v12; // [rsp+14h] [rbp-16Ch]
  __int16 v13[10]; // [rsp+18h] [rbp-168h] BYREF
  __int16 v14[10]; // [rsp+2Ch] [rbp-154h] BYREF
  char v15[32]; // [rsp+40h] [rbp-140h] BYREF
  char v16[32]; // [rsp+60h] [rbp-120h] BYREF
  char v17[48]; // [rsp+80h] [rbp-100h] BYREF
  char v18[48]; // [rsp+B0h] [rbp-D0h] BYREF
  char s[64]; // [rsp+E0h] [rbp-A0h] BYREF
  char v20[72]; // [rsp+120h] [rbp-60h] BYREF
  unsigned __int64 v21; // [rsp+168h] [rbp-18h]

  v21 = __readfsqword(0x28u);
  init(argc, argv, envp);
  strcpy(v17, "You don't have access to KrackMe 1.0 !");
  strcpy(v18, "Since you are here let me ask you something...");
  strcpy(v15, "Please enter the flag : ");
  strcpy(v16, "Oh My God ! What is that ?");
  strcpy(v20, "Did you know, Bangladesh has the longest natural beach?...");
  if ( argc != 5 ) //kiểm tra số lượng tham số đầu vào là 5
  {
    for ( i = 0; i <= 0x26; ++i )
    {
      putchar(v17[i]);
      fflush(_bss_start);
      usleep(0x186A0u);
    }
    putchar(10);
    for ( j = 0; j <= 0x2E; ++j )
    {
      putchar(v18[j]);
      fflush(_bss_start);
      usleep(0x186A0u);
    }
    putchar(10);
    for ( k = 0; k <= 0x3A; ++k )
    {
      putchar(v20[k]);
      fflush(_bss_start);
      usleep(0x186A0u);
    }
    putchar(10);
    exit(0);
  }
  for ( m = 0; m <= 0x18; ++m )
  {
    putchar(v15[m]);
    fflush(_bss_start);
    usleep(0x186A0u);
  }
  fgets(s, 50, stdin);
  if ( strlen(s) != 40 ) // kiểm ra kích thước của chuỗi là 40
  {
    for ( n = 0; n <= 0x1A; ++n )
    {
      putchar(v16[n]);
      fflush(_bss_start);
      usleep(0x186A0u);
    }
    putchar(10);
    exit(0);
  }
  strcpy((char *)v13, "mer`]MtGe");
  strcpy((char *)&v13[5], "aUG9UeDoU");
  strcpy((char *)v14, "(G~Ty_G{(");
  strcpy((char *)&v14[5], "v}QlOto|s");
  v12 = 0;
  for ( ii = 0; ii < strlen((const char *)v13); ++ii ) //kiểm tra của chuỗi đúng hay sai nếu sai 1 trong các điều kiện sẽ out program.
  {
    if ( *((_BYTE *)v13 + ii) != ((unsigned __int8)(v20[14] ^ v16[8]) ^ (unsigned __int8)s[ii]) )
    {
      v12 = 0;
      break;
    }
    if ( *((_BYTE *)&v14[5] + ii) != ((unsigned __int8)(v17[11] ^ v17[1]) ^ (unsigned __int8)s[ii + 27]) )
    {
      v12 = 0;
      break;
    }
    if ( *((_BYTE *)&v13[5] + ii) != ((unsigned __int8)(v17[1] ^ HIBYTE(v13[0])) ^ (unsigned __int8)s[ii + 9]) )
    {
      v12 = 0;
      break;
    }
    if ( *((_BYTE *)v14 + ii) != ((unsigned __int8)(HIBYTE(v14[5]) ^ HIBYTE(v13[0])) ^ (unsigned __int8)s[ii + 18]) ) //func HIBYTE()
    {
      v12 = 0;
      break;
    }
    v12 = 1;
  }
  if ( v12 == 1 ) //check in ra flag
  {
    puts("Congratulations !! ");
    printf("Flag : ");
    for ( jj = 0; jj <= 35; ++jj )
    {
      putchar(s[jj]);
      fflush(_bss_start);
      usleep(0x186A0u);
    }
    putchar(10);
  }
  else
  {
    for ( kk = 0; kk <= 0x1A; ++kk )
    {
      putchar(v16[kk]);
      fflush(_bss_start);
      usleep(0x186A0u);
    }
  }
  return 0;
}

Như đã phân tích trên thì sẽ cũng ra được bài rồi. Và dưới đây là code python của tôi:

v13 = "mer`]MtGe "
v13a = "aUG9UeDoU "
v14 = "(G~Ty_G{( "
v14a = "v}QlOto|s "
v17 = "You don't have access to KrackMe 1.0 !"
v18 = "Since you are here let me ask you something..."
v16 = "Oh My God ! What is that ?"
v20 = "Did you know, Bangladesh has the longest natural beach?..."

for i in range(0,9):
    for j in range(0,127):
        if ord(v13[i]) == ord(v20[14]) ^ ord(v16[8])^j:
            print(chr(j), end='') 
print('\n')

# KCTF{kRaC♠
for i in range(0,10):
    for j in range(0,127):
        if ord(v14a[i]) == ord(v17[11]) ^ ord(v17[1])^j:
            print(chr(j), end='')
print('\n')
# xs_bAzar}.

for i in range(0,10):
    for j in range(0,127):
        if ord(v13a[i]) == ord(v17[1]) ^ ord(v13[1])^j: # nó lấy giá trị HIBYTE của v13[0] 16bit là 'me' mà trong assembly -> HIBYTE sẽ nhận là 'e'
            print(chr(j), end='') 
print('\n')
# k_M3_oNe_*

for i in range(0,10):
    for j in range(0,127):
        if ord(v14[i]) == ord(v14a[1]) ^ ord(v13[1])^j:
            print(chr(j), end='') 
print('\n')
# 0_fLaG_c08

Vậy ta sắp xếp lại theo thứ tự thì ta được flag: KCTF{kRaCk_M3_oNe_0_fLaG_c0xs_bAzar}.

2: The Activator (Solved)

title

Code hàm main:

main

Phần trên là phần show màn hình và cin cái mà mình cần nhập. Tiếp đến là phần kiểm tra cái mà mình nhập:

check flag

Nó sẽ kiểm ra thông qua các func con khác để tạo thành 1 keygen hoản chỉnh và nếu không thỏa mãn 1 trong các điều kiện đó thì sẽ được nhảy đến phần này luôn:

jump if false

Với bài này thì ta chỉ cần đọc lần lượt các hàm yêu cầu rồi viết lại các điều kiện đó và tạo keygen thôi. Dưới là tôi viết chương trình py, khi chạy thì chương trình sẽ cho bạn 1 keygen random.

from random import choice

p1 = []
p2 =[]
p3 = 'KOS'
p4 = []
p5 = []

# part 1 three number
for i in range(0,10):
    for j in range(0,10):
        for k in range(0,10):
            temp = int(str(i) + str(j) + str(k))
            if temp > 0 and temp < 366 and temp !=333:
                p1.append(str(i) + str(j) + str(k))

# part 2 two number continue
for i in range(0,10):
    for j in range(0,10):
        temp = int(str(i) +str(j))
        if temp ==95 or temp==96 or temp ==97 or temp==98 or temp ==99 or temp <=2:
            p2.append(str(i) +str(j))

#part 4 
for i in range(0,10):
    for j in range(0,10):
        for k in range(0,10):
            for l in range(0,10):
                for m in range(0,10):
                    for n in range(0,10):
                        for o in range(0,10):
                            temp = i +j+k+m+n+l+o
                            if temp % 7 ==0:
                                p4.append(str(i) +str(j)+str(k) +str(l)+str(m) +str(n)+str(o))

#part 5
for i in range(0,10):
    for j in range(0,10):
        for k in range(0,10):
            for l in range(0,10):
                for m in range(0,10):
                    if i <=9 and j <=9 and k <=9 and l <=9 and m <=9:
                        p5.append(str(i) +str(j)+str(k) +str(l)+str(m))


keygen = choice(p1) + choice(p2) + '-' + p3 + '-'+ choice(p4) + '-' + choice(p5)

print(keygen)

# KCTF{Th47_License_ch3cker_w4S_similar_t0_Wind0ws_95_OSR_Activator_Right?}

Lưu ý chương trình tôi viết nó hàn lâm quá vì chỉ các vòng lặp đơn giản, có cách khác là ta sự dụng các hàm sẵn của python thì sẽ thấy code ngăn hơn.

3: The Defuser (Solved)

title

Với bài này thì ta cần điền nhanh trước khi bom nổ:

main

  • Hàm signal() là gì?
    • Trong thư viện C thì hàm void (*signal(int sig, void (*func)(int)))(int) để xử lý tín hiệu (handle signal), tức là một trình xử lý tín hiệu với số tín hiệu sig.
    • sig - Đây là số tín hiệu mà chức năng xử lý được đặt. Và sau đây là một số tín hiệu tiêu biểu quan trọng:
      • SIGABRT - (Signal Abort) - Chấm dứt bất thường, chẳng hạn như được khai báo bởi func.
      • SIGFPE- (Signal Floating-Point Exception) - phép toán số học sai, chẳng hạn như phép chia bằng 0 hoặc pháp toán dẫn đến tràn số (không nhất thiết phải có phép toán dấu phẩy động).
      • SIGILL - (Signal Illegal Instruction) - invalid function image, chẳng hạn như câu lệnh không hợp lệ. Điều này thường do code bị hỏng hoặc cố gáng thực thi dữ liệu.
      • SIGINT - (Signal Interrupt) - tín hiệu chú ý tương tác. Thường được tạo bởi người dùng ứng dụng.
      • SIGSEGV - (Signal Segmentation Violation) - truy cập không hợp lệ vào bộ lưu trữ. Khi một chương trình cố gắng đọc hoặc ghi bên ngoài bộ nhớ, nó được cấp phát cho nó.
      • SIGTERM - (Signal Terminate) - yêu cầu chấm dứt gửi đến chương trình.
  • Hàm alarm() sẽ khiến hệ thống tạo tín hiệu SIGALRM cho quy trình sau khi hết số giây thời gian thực được chỉ định bằng giây.

Như vậy sau đó chương trình sẽ yêu cầu ta nhập gì đó để kiểu cầu xin họ cho bom không nổ🥲. và sau đó xử lý nó ở hàm sub_2760():

sub_2760

Rồi tôi debug nó xem sau: tất nhiên khi debug đến alarm(1) thì chương trình sẽ dừng về nó sẽ đưa tín cho trình xử lý để dừng chương trình. Do đó khi debug qua nó thì tôi sửa 1 thành 1 thời gian bao la…; rồi nhập -> đi vào hàm sub_2760() -> đến câu lệnh so sánh sửa cờ để chỉ hướng vào trong hàm sub_2596() (hoặc sửa giá trị a1 như trên) -> rồi ta thấy chương trình sẽ giải mã và in ra cho ta flag….:

result

4: Help Jimmy (Solved)

title

Bài này là một game chọn đường đi cho Jimmy xem cho anh ấy đi lên rừng hay xuống biển. Ấy vậy khi chạy chọn 1 hay 2 đều chết))).

Code của main:

main

Một đoạn không hiểu thế làm thế nào để chọn đường cho đúng. Nên lúc đầu tôi tin vào F5 của IDA thế nên tôi bỏ qua nó sang task khác thì xong nhận được trợ giúp từ đồng đội thì tôi xem asm language của nó thì nhận ra trước khi nhập 1 hoặc 2 thì có so sánh và tôi cũng có thắc mắc tại sao lại gán 2 giá trị v23[1]v23[2] cho 5 rồi để không. Thì ra nó só sánh 2 cái đó nếu bằng nhau thì ra đến phần luôn sai thế nên debug tôi sẽ sửa và tiếp tục xem sa0:

jz

và rồi khi đến phần be bé đó ta đến với hàm giải mã flag và ra luôn flag hí hì:

result

5: Fan

title

Với thử thách này thì bài cho ta 1 file chưa code viết bằng python đã dùng dis() để thành các bytecode. Nhiệm vụ của chúng ta là dịch lại thành code nguyên bản để đọc chương trình ra flag. Và sau đây tôi sẽ cùng các bạn phân tích lần lượt như sau nhé:

# Method Name:       <module>
# Filename:          chall.py
# Argument count:    0
# Keyword-only arguments: 0
# Number of locals:  0
# Stack size:        5
# Flags:             0x00000040 (NOFREE)
# First Line:        1
  1:           0 LOAD_CONST           (<code object define_false at 0x7fbea9c650c0, file "chall.py", line 1>)
               2 LOAD_CONST           ('define_false')
               4 MAKE_FUNCTION        (Neither defaults, keyword-only args, annotations, nor closures)
               6 STORE_NAME           (define_false)

 19:           8 LOAD_CONST           (<code object define_true at 0x7fbea9c65540, file "chall.py", line 19>)
              10 LOAD_CONST           ('define_true')
              12 MAKE_FUNCTION        (Neither defaults, keyword-only args, annotations, nor closures)
              14 STORE_NAME           (define_true)

 25:          16 LOAD_CONST           (<code object define_both at 0x7fbea9699540, file "chall.py", line 25>)
              18 LOAD_CONST           ('define_both')
              20 MAKE_FUNCTION        (Neither defaults, keyword-only args, annotations, nor closures) 
              22 STORE_NAME           (define_both)

 40:          24 LOAD_NAME            (__name__)
              26 LOAD_CONST           ('__main__')
              28 COMPARE_OP           (==)
              30 POP_JUMP_IF_FALSE    (to 66)  # nhảy đến vị trí số 66 nếu điều kiện không thỏa mãn

 41:          32 LOAD_CONST           ('chr(75)chr(67)chr(84)chr(70)chr(123)')
              34 LOAD_CONST           ('chr(115)chr(105)chr(85)chr(85)chr(85)')
              36 LOAD_CONST           ('chr(109)chr(69)chr(51)chr(115)chr(115)chr(105)')
              38 LOAD_CONST           ('chr(105)chr(115)')
              40 LOAD_CONST           ('chr(103)chr(48)chr(79)chr(97)chr(116)chr(125)')
              42 BUILD_LIST           5
              44 STORE_NAME           (s)

 42:          46 LOAD_NAME            (print)
              48 LOAD_NAME            (define_false)
              50 LOAD_NAME            (define_true)
              52 LOAD_NAME            (define_both)
              54 LOAD_NAME            (s)
              56 CALL_FUNCTION        (1 positional argument)
              58 CALL_FUNCTION        (1 positional argument)
              60 CALL_FUNCTION        (1 positional argument)
              62 CALL_FUNCTION        (1 positional argument)
              64 POP_TOP
         >>   66 LOAD_CONST           (None)
              68 RETURN_VALUE

Câu lệnh được sử dụng để disassemble python là python -m dis name_file.py hoặc là dis.dis(obj) - lưu ý nhớ import dis. Một lưu ý nữa là khi LOAD_CONST sẽ được tải ngược lại, giống như stack vào trước ra sau.

1, 19, 25, 40 là các vị trí đặt các hàm của chương trình. đầu tiên sẽ là định nghĩa hàm define_false(), define_true, define_both, __main__. Một số câu lệnh cần biết:

  • STORE_NAME - là để biểu thị tên biến được tạo gán, hoặc lưu trữ. Thường đi kèm với bytecode LOAD_CONST thực hiện việc gán dl cho biến
  • COMPARE_OP - toán tử so sánh
  • POP_JUMP_IF_FALSE - nhảy tuyệt đối nếu điều kiện sai
  • BUILD_LIST - tạo list
  • POP_TOP - removes the top-of-stack (TOS) item.
  • RETURN_VALUE - returns with TOS to the caller of the function.

Và sau đây tôi sẽ viết lại code:

def define_false(arg):
  pass

def define_true(arg):
  pass

def define_both(arg):
  pass

if __name__ == '__main__':
    s = [
    'chr(103)chr(48)chr(79)chr(97)chr(116)chr(125)',
    'chr(105)chr(115)',
    'chr(109)chr(69)chr(51)chr(115)chr(115)chr(105)',
    'chr(115)chr(105)chr(85)chr(85)chr(85)',
    'chr(75)chr(67)chr(84)chr(70)chr(123)'
    ]# list gồm 5 phần tử
    s = s[::-1]
    print(define_false(define_true(define_both(s))))

Tiếp theo nhé:

# Method Name:       define_false
# Filename:          chall.py
# Argument count:    1
# Keyword-only arguments: 0
# Number of locals:  7
# Stack size:        4
# Flags:             0x00000043 (NOFREE | NEWLOCALS | OPTIMIZED)
# First Line:        1
  2:           0 BUILD_LIST           0
               2 STORE_FAST           (lstr)

  3:           4 LOAD_CONST           (0)
               6 STORE_FAST           (u)

  4:           8 LOAD_CONST           ('')
              10 STORE_FAST           (packed)

  5:          12 SETUP_LOOP           (to 126)
              14 LOAD_FAST            (s)
              16 GET_ITER
         >>   18 FOR_ITER             (to 124)
              20 STORE_FAST           (c)

  6:          22 LOAD_FAST            (c)
              24 LOAD_CONST           ('[')
              26 COMPARE_OP           (==)
              28 POP_JUMP_IF_FALSE    (to 54)

  7:          30 LOAD_FAST            (lstr)
              32 LOAD_ATTR            (append)
              34 LOAD_FAST            (packed)
              36 LOAD_FAST            (u)
              38 BUILD_TUPLE          2
              40 CALL_FUNCTION        (1 positional argument)
              42 POP_TOP

  8:          44 LOAD_CONST           ('')
              46 STORE_FAST           (packed)

  9:          48 LOAD_CONST           (0)
              50 STORE_FAST           (u)
              52 JUMP_ABSOLUTE        (to 18)

 10:     >>   54 LOAD_FAST            (c)
              56 LOAD_CONST           (']')
              58 COMPARE_OP           (==)
              60 POP_JUMP_IF_FALSE    (to 88)

 11:          62 LOAD_FAST            (lstr)
              64 LOAD_ATTR            (pop)
              66 CALL_FUNCTION        (0 positional arguments)
              68 UNPACK_SEQUENCE      2
              70 STORE_FAST           (prev_string)
              72 STORE_FAST           (num)

 12:          74 LOAD_FAST            (prev_string)
              76 LOAD_FAST            (num)
              78 LOAD_FAST            (packed)
              80 BINARY_MULTIPLY
              82 BINARY_ADD
              84 STORE_FAST           (packed)
              86 JUMP_ABSOLUTE        (to 18)

 13:     >>   88 LOAD_FAST            (c)
              90 LOAD_ATTR            (isdigit)
              92 CALL_FUNCTION        (0 positional arguments)
              94 POP_JUMP_IF_FALSE    (to 114)

 14:          96 LOAD_FAST            (u)
              98 LOAD_CONST           (10)
             100 BINARY_MULTIPLY
             102 LOAD_GLOBAL          (int)
             104 LOAD_FAST            (c)
             106 CALL_FUNCTION        (1 positional argument)
             108 BINARY_ADD
             110 STORE_FAST           (u)
             112 JUMP_ABSOLUTE        (to 18)

 16:     >>  114 LOAD_FAST            (packed)
             116 LOAD_FAST            (c)
             118 INPLACE_ADD
             120 STORE_FAST           (packed)
             122 JUMP_ABSOLUTE        (to 18)
         >>  124 POP_BLOCK

 17:     >>  126 LOAD_FAST            (packed)
             128 RETURN_VALUE
  • LOAD_GLOBAL - load biến toàn cục
  • BUILD_TUPLE - tạo typle (số lượng)
  • JUMP_ABSOLUTE - nhảy tuyệt đối
  • UNPACK_SEQUENCE unpack TOS into count các giá trị riêng lẻ, được put onto the stack right-to-left
  • BINARY_MULTIPLY - biểu thức nhân
  • BINARY_ADD - cộng
def define_false(s):
    lstr = []
    u = 0
    packed = ''
    for c in s:
        if  c == '[':
            lstr.append((u, packed))
            packed = ''
            u = 0
            continue
        if c == ']':
            num, prev_string = lstr.pop()
            packed = prev_string + packed * num 
            continue
        if c.isdigit():
            u = u* 10 + int(c)
            continue
        packed = packed + c
    return packed

Tiếp:

# Method Name:       define_true
# Filename:          chall.py
# Argument count:    1
# Keyword-only arguments: 0
# Number of locals:  3
# Stack size:        5
# Flags:             0x00000043 (NOFREE | NEWLOCALS | OPTIMIZED)
# First Line:        19
 20:           0 LOAD_CONST           ('')
               2 STORE_FAST           (res)

 21:           4 SETUP_LOOP           (to 42)
               6 LOAD_FAST            (p)
               8 GET_ITER
         >>   10 FOR_ITER             (to 40)
              12 STORE_FAST           (packed)

 22:          14 LOAD_FAST            (res)
              16 LOAD_GLOBAL          (str)
              18 LOAD_GLOBAL          (len)
              20 LOAD_FAST            (packed)
              22 CALL_FUNCTION        (1 positional argument)
              24 CALL_FUNCTION        (1 positional argument)
              26 LOAD_CONST           ('[:]')
              28 BINARY_ADD
              30 LOAD_FAST            (packed)
              32 BINARY_ADD
              34 INPLACE_ADD
              36 STORE_FAST           (res)
              38 JUMP_ABSOLUTE        (to 10)
         >>   40 POP_BLOCK

 23:     >>   42 LOAD_FAST            (res)
              44 RETURN_VALUE

1 Lưu ý là ta đọc từ dưới lên đối với 1 câu lệnh gán (và tất nhiên là từ phải qua trái)

def define_true(p):
    res = ''
    for packed in p:
        res += str(len(packed)) + '[:]' + packed
    return res

và hàm cuối cùng trước khi chạy xem sao:

# Method Name:       define_both
# Filename:          chall.py
# Argument count:    1
# Keyword-only arguments: 0
# Number of locals:  6
# Stack size:        5
# Flags:             0x00000043 (NOFREE | NEWLOCALS | OPTIMIZED)
# First Line:        25
 26:           0 BUILD_LIST           0
               2 STORE_FAST           (unpacked)

 27:           4 SETUP_LOOP           (to 86)
               6 LOAD_FAST            (p)
               8 GET_ITER
         >>   10 FOR_ITER             (to 84)
              12 STORE_FAST           (i)

 28:          14 LOAD_FAST            (i)
              16 LOAD_ATTR            (split)
              18 LOAD_CONST           (')')
              20 CALL_FUNCTION        (1 positional argument)
              22 STORE_FAST           (packed)

 29:          24 LOAD_CONST           ('')
              26 STORE_FAST           (char)

 30:          28 SETUP_LOOP           (to 72)
              30 LOAD_FAST            (packed)
              32 GET_ITER
         >>   34 FOR_ITER             (to 70)
              36 STORE_FAST           (j)

 31:          38 LOAD_FAST            (j)
              40 LOAD_CONST           ('')
              42 COMPARE_OP           (==)
              44 POP_JUMP_IF_FALSE    (to 48)

 32:          46 BREAK_LOOP

 33:     >>   48 LOAD_FAST            (j)
              50 LOAD_CONST           (')')
              52 INPLACE_ADD
              54 STORE_FAST           (j)

 35:          56 LOAD_FAST            (char)
              58 LOAD_GLOBAL          (eval)
              60 LOAD_FAST            (j)
              62 CALL_FUNCTION        (1 positional argument)
              64 INPLACE_ADD
              66 STORE_FAST           (char)
              68 JUMP_ABSOLUTE        (to 34)
         >>   70 POP_BLOCK

 36:     >>   72 LOAD_FAST            (unpacked)
              74 LOAD_ATTR            (append)
              76 LOAD_FAST            (char)
              78 CALL_FUNCTION        (1 positional argument)
              80 POP_TOP
              82 JUMP_ABSOLUTE        (to 10)
         >>   84 POP_BLOCK

 37:     >>   86 LOAD_FAST            (unpacked)
              88 RETURN_VALUE
  • BREAK_LOOP - câu lệnh break
def define_both(p):
    unpacked = []
    for i in p:
        packed = i.split(')')
        char = ''
        for j in packed:
            if j == '':
                break
            j  += ')'
            char += eval(j)
        unpacked.append(char)
    return unpacked

Và tổng hợp vào và chạy ta được:

def define_both(p):
    unpacked = []
    for i in p:
        packed = i.split(')')
        char = ''
        for j in packed:
            if j == '':
                break
            j  += ')'
            char += eval(j)
        unpacked.append(char)
    return unpacked

def define_true(p):
    res = ''
    for packed in p:
        res += str(len(packed)) + '[:]' + packed
    return res

def define_false(s):
    lstr = []
    u = 0
    packed = ''
    for c in s:
        if  c == '[':
            lstr.append((u, packed))
            packed = ''
            u = 0
            continue
        if c == ']':
            num, prev_string = lstr.pop()
            packed = prev_string + packed * num 
            continue
        if c.isdigit():
            u = u* 10 + int(c)
            continue
        packed = packed + c
    return packed

if __name__ == '__main__':
    s = [
    'chr(103)chr(48)chr(79)chr(97)chr(116)chr(125)',
    'chr(105)chr(115)',
    'chr(109)chr(69)chr(51)chr(115)chr(115)chr(105)',
    'chr(115)chr(105)chr(85)chr(85)chr(85)',
    'chr(75)chr(67)chr(84)chr(70)chr(123)'
    ]# list gồm 5 phần tử
    s = s[::-1]
    print(define_false(define_true(define_both(s))))
#KCTF{:::::siUUU::::::mEssi::::::::::::::::::::::::::::::::is::::::gOat}

6: Stegorev

title

Trong nhiệm vụ lần này thì cho ta một bức ảnh thôi, với tiêu đề Stegorev thì chắc chắn bài này ta cần tìm thông tin hay file bị giấu ở ảnh này để từ đó reverse nó ra.

Khi ta tìm kiếm các thủ thuật, Hacktricks về stego, thì đã tìm được stegcracker dùng để bung file đó ra xem có gì không. Sau một thời gian chờ đợi password thì cuối cùng cũng ra (thư viện password mặc định) một file thực thi trên linux.

Với cả xem tham khảo thêm thì ta nhận được thêm 1 tool nữa là Stegseek.

Quả thật nhanh chưa đầy 3s ấy vậy mà trước mình phải chờ hẳn 30 phút🥲. (link tham khảo writeup này nè )

stegseek

Ta nhận được file kctf-rng70.jpg.out tiếp theo đến phần reverse. Kiểm tra bằng ida pro thì phát hiện là đầu tiên kiểm tra xem có tồn tại file với tên ckrIupRS782prsdsf:

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 v3; // rax
  char v5[32]; // [rsp+0h] [rbp-A0h] BYREF
  char v6[47]; // [rsp+20h] [rbp-80h] BYREF
  char v7; // [rsp+4Fh] [rbp-51h] BYREF
  char v8[32]; // [rsp+50h] [rbp-50h] BYREF
  char v9[40]; // [rsp+70h] [rbp-30h] BYREF

  std::allocator<char>::allocator(&v7, a2, a3);
  std::string::basic_string(v6, "ckrIupRS782prsdsf", &v7); //cái này để truyền địa chỉ cho v6 trỏ tới chuỗi ckrIupRS782prsdsf
  sub_2486(v5, v6); // cần check
  std::string::~string(v6);
  std::allocator<char>::~allocator(&v7);
  if ( (unsigned __int8)sub_2C13(v5, "The file maybe lost in the matrix. Try hard to find it") ) //hàm này để so sánh nếu bằng với chuỗi này thì exit
    exit(0);
  std::string::basic_string(v9, v5);
  sub_266F(v8, v9);
  v3 = std::operator<<<char>(&std::cout, v8);
  std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
  std::string::~string(v8);
  std::string::~string(v9);
  std::string::~string(v5);
  return 0LL;
}

Chúng ta cùng đi vào hàm sub_2486() kiểm tra xem trong làm gì:

__int64 __fastcall sub_2486(__int64 a1, __int64 a2)
{
  __int64 v2; // rdx
  __int64 v3; // rax
  __int64 v4; // rax
  char v6[32]; // [rsp+10h] [rbp-240h] BYREF
  char v7[527]; // [rsp+30h] [rbp-220h] BYREF
  char v8[9]; // [rsp+23Fh] [rbp-11h] BYREF

  std::ifstream::basic_ifstream(v7);
  std::ifstream::open(v7, a2, 8LL);
  if ( (unsigned __int8)std::ifstream::is_open(v7) ) // mở file có tên v7 là v2 mà mình đã bàn lúc nãy
  {
    std::string::basic_string(v6);
    std::operator>><char>(v7, v6);
    v3 = std::operator<<<std::char_traits<char>>(&std::cout, "Flag: ");
    v4 = std::operator<<<char>(v3, v6);
  }
  else
  {
    std::allocator<char>::allocator(v8, a2, v2);
    std::string::basic_string(v6, "The file maybe lost in the matrix. Try hard to find it", v8);
    std::allocator<char>::~allocator(v8);
    v4 = std::operator<<<char>(&std::cout, v6);
  }
  std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
  std::string::basic_string(a1, v6);
  std::string::~string(v6);
  std::ifstream::~ifstream(v7);
  return a1;
}

Hàm này kiểm tra xem có file tên ckrIupRS782prsdsf có tồn tại không? nếu có in ra flag còn nếu không thì sẽ in và gán cho nó chuỗi rồi return chuỗi The file maybe lost in the matrix. Try hard to find it.

Như vậy nếu thỏa mãn thì ta sẽ nhận được như sau:

open file

Như vậy là đã thỏa mãn việc tồn tại file nhưng vẫn không ra đúng. Kiểm tra lại ta thấy là họ lấy giá trị có trong file mình vừa tạo mà lúc nãy mình tạo file rỗng.

Sau khi debug lại ta có: ta truyền dữ liệu bất kì cho file đó rồi chạy thì hiện ra flag kiểu so sánh ?==? với JBVE~k_lRciOX*=(HG=,0KKEl mà không biết cái này là gì😂.

Thế là sửa file đó ném vào file đó cái đó thì ta nhận được flag hí hí….

result

Như vậy là xong bài được nhiều điểm nhất mà tôi cũng tiếc nhất vì làm được đến coi như là 90% hơn rồi.

Cảm ơn mọi người đã đọc đến đây. Hẹn mọi người tại các bài viết khác nhé… Chúc mọi người thành công.🏆

results matching ""

    No results matching ""