picoCTF 2022 Write Up


We participated in picoCTF 2022 held in March 2022. Last year I competed as an individual, but this year I am competing as Team TaruTaru. Taru Taru was in 595th place with 9200 points. I have to work harder...

I wrote Write Up about the problem I solved. I have quite a bit of overlap with my teammates. The actual code I used is on GitHub. There is no readability at all, so if you have any concerns, please feel free to ask.

Binary Exploitation

buffer overflow 0 (100pts)

Distributed vuln.c include

int main(int argc, char **argv){
  signal(SIGSEGV, sigsegv_handler);

There exists a function called , and the contents of the sigsegv_handler are

void sigsegv_handler(int sig) {
", flag);

It has become. So it seems that if you raise a Segmentation Fault during execution, the sigsegv_handler will be executed and the flag will be output. The contents of the vuln function executed within the main function are

void vuln(char *input){
  char buf2[16];
  strcpy(buf2, input);

and assume that input is less than 16 characters, but this input is used in main function

int main(int argc, char **argv){
  char buf1[100];

It is possible to pass up to 100 characters (including null characters) in the form of. Therefore, if you send a large number of characters to the program, a Segmentation Fault will occur and a flag will be displayed.

CVE-XXXX-XXXX (100pts)

If you do a Google search on "Windows Print Spooler Service CVE", the IPA website comes up first. The CVE number is CVE-2021-34527. Is the genre of this issue Binary Explotion???

RPS (200pts)

Play rock-paper-scissors with the server, and if you win 5 games in a row, you will get a flag. The judgment of victory or defeat is

char* loses[3] = {"paper", "scissors", "rock"};
if (strstr(player_turn, loses[computer_turn])) {
  puts("You win! Play again?");
  return true;
} else {
  puts("Seems like you didn't win this time. Play again?");
  return false;

It is implemented in: palyer_turn is a string of user input, and computer_turn is a random number of 0~2. strstr(const char *s1, const char *s2) returns the starting position of the string s1 when it contains the string s2, so if you enter rockscissorspaper as input, it will be judged as a victory no matter what the opponent's hand is. Repeat this 5 times and the flag will appear.


basic-mod1 (100pts)

It seems that you can calculate the number mod37 described in message.txt and replace it with A-Z if its value is 0-25, 0-9 if it is 26-35, and _ if it is 36. Write a script and run it.

print("picoCTF{", end="")
with open("message.txt", "r") as fp:
\tfor n in fp.read().strip().split(" "):
\t\tn = int(n)
\t\tn = n%37
\t\tif n==36:
\t\t\tprint("_", end="")
\t\telif n>=26:
\t\t\tprint(n-26, end="")
\t\t\tprint(chr(ord('a')+n), end="")


basic-mod2 (100pts)

Calculate the inverse of the number in mod41 described in message.txt and replace it with A-Z if the value is 1-26, 0-9 if it is 27-36, and _ if it is 37.

x*y \\equiv 1\\ (mod\\ n)

When holds, y is called the inverse (in mod n) of x. There is an algorithm that efficiently computes the inverse source, but with mod 41, it is OK to calculate it by full search.

def get_inv(i):
    for j in range(1, 41):
        if (i*j)%41==1:
            return j
    return 999

print("picoCTF{", end="")
with open("message.txt", "r") as fp:
    for n in fp.read().strip().split(" "):
        n = int(n)
        n = get_inv(n)
        if n==37:
            print("_", end="")
        elif n>=27:
            print(n-27, end="")
            print(chr(ord('a')+n-1), end="")


rail-fence (100pts)

You can decode it in CyberChef.

substitution0 (100pts)

A single substitution cipher. At the end of the sentence Pmj tuec xg: fxslSPT{...} would obviously replace The flag is: picoCTF{...}. The flag consists of uppercase letters, but the rest of the sentence is only lowercase, so it seems impossible to specify the replacement destination of the uppercase case if the substitution is different in the case, so maybe the case substitution destination is the same... I feel it. Or rather, I hope so. All that's left is to find a word like that and identify the replacement destination one letter at a time.

substitution1 (100pts)

It is also a single transliteration cipher. eqs coxa dj: zdifIEC{...} would have replaced the flag is: picoCTF{...}. I will replace the rest with my spirit.

substitution2 (100pts)

The moment I see the ciphertext, I feel like I'm going to get a kick out of it, but I hold back and take a sip of my coffee. From the flow so far, it is a single transliteration cipher, and the gvjnxqceupemzMGN{...} is a substitute for the theflagispicoCTF{...}. The rest is spirit. It's the spirit. They don't know anything about frequency analysis.

Vigenere (100pts)

I was able to decode it in CyberChef.

diffie-hellman (200pts)

Alice and Bob shared a secret value in a Diffie Hermann key exchange and used that value to encrypt plaintext with the Caesar cipher. Since the value used for the Diffie Hermann key exchange is small across the board, it seems that it can be easily decrypted, but even if you do not think about such a small difficulty, the last is Caesar cipher, so it is OK if you combine it with force work. It was C4354R_C1PH3R_15_4_817_0U7D473D_84AA1DA8 that seemed to have meaning as plain text, so if you wrap it with picoCTF{}, it becomes a flag.


Enhance! (100pts)

When I open the distributed SVG file in a text editor

         id="tspan3748">p </tspan><tspan
         id="tspan3754">i </tspan><tspan
         id="tspan3756">c </tspan><tspan
         id="tspan3758">o </tspan><tspan
         id="tspan3760">C </tspan><tspan
         id="tspan3762">T </tspan><tspan
         id="tspan3764">F { 3 n h 4 n </tspan><tspan
         id="tspan3752">c 3 d _ a a b 7 2 9 d d }</tspan></text>

You can see the flag being filled in.

File types (100pts)

The extension of the distributed file is .pdf, but when I check the file type with file command,

% file Flag.pdf 
Flag.pdf: shell archive text

is displayed. This is

% sh Flag.pdf

It can be defrosted by . In this way, if you repeatedly examine the file type with file command → unzip it in the corresponding application, you will eventually get


You will get a text file with the contents of . Apparently it looks like Hex, so when I decoded it in CyberChef it showed up flags.

Lookey here (100pts)

% cat anthem.flag.txt | grep pico
      we think that the men of picoCTF{[email protected]_4c479940}

Packets Primer (100pts)

When I read the distributed pcap file with Wireshark, I got a flag.スクリーンショット 2022-03-18 2.03.16.png

Redaction gone wrong (100pts)

Some parts of the document are blacked out, but you can read them by dragging them, copying them, and then pasting them into a text editor.

Sleuthkit Intro (100pts)

When I run mmls

% mmls disk.img
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

      Slot      Start        End          Length       Description
000:  Meta      0000000000   0000000000   0000000001   Primary Table (#0)
001:  -------   0000000000   0000002047   0000002048   Unallocated
002:  000:000   0000002048   0000204799   0000202752   Linux (0x83)

It comes to. When you access the server, it asks for What is the size of the Linux partition in the given disk image?, so you can send a 202752 to get the flag.

Eavesdrop (300pts)

Under construction...

SideChannel (400pts)

A binary called pin_checker is distributed and when you run it, it asks you to "Please enter your 8-digit PIN code:". When I tried typing "000000000", I got "Access denied." It was displayed. Entering the appropriate 8-digit PIN code will probably succeed in Access. The title of the problem is "SideChannel" and the hint is "Read about timing-based side-channel attacks." And from what is written, the PIN code (part of ?) It seems that the execution time will change depending on whether it matches the correct answer or not. It seems that the correct PIN code is considered to be an 8-digit number, so there are only $10^8$ of 99999999 from 0000000000. Let's try it all out. First, if you look at the binaries in strings, you'll see a message that says "Access granted. You may use your PIN to log into the master server." You can see that the message is prepared. If you enter the correct PIN code, you will see this message. After that, assemble an appropriate shell and perform a full search until the correct answer message comes out.

% seq 0 99999999 | xargs -t -P1024 -r -I @ sh -c 'echo @ && printf "%08d\
" "@" | ./pin_checker ' > log.txt

This shell script is a script that "performs 1024 parallel processing of "displaying the number from 0 to 99999999 and then passing it to the pin_checker (by filling in 0 in 8 digits)". When I ran parallel execution on the 32-core, 64-thread AMD Ryzen ThreadRipper 3970X, it looked like it would be over in about four days. In fact, after 2 days, I received the above correct answer message. Note that the script above does not do any sort of exclusive control when writing to the log.txt, so other threads are writing a lot between when the correct PIN code is written to the file and when the correct answer message is written. That said, it's safe to assume that the correct PIN code is also written near the correct answer.

% cat log.txt | grep -3 granted
Please enter your 8-digit PIN code:
Checking PIN...
Access granted. You may use your PIN to log into the master server.
Please enter your 8-digit PIN code:

Apparently, the correct PIN code is around the 48390594. Again, explore this area without parallel processing.

% seq 48389600 48390600 | xargs -t -r -I@ sh -c 'echo @ && printf "%08d\
" "@" | ./pin_checker ' > log2.txt
% cat log2.txt | grep -5 granted
Access denied.
Please enter your 8-digit PIN code:
Checking PIN...
Access granted. You may use your PIN to log into the master server.
Please enter your 8-digit PIN code:
Checking PIN...
Access denied.

The correct PIN code was 48390513. Then you can send it to the server and get the flag. I feel like I did all this last year. Seriously.

Revers Engineering

file-run1 (100pts)

% strings run | grep pico

file-run2 (100pts)

% strings run | grep pico

I didn't need to do it...

GDB Test Drive (100pts)

After downloading the distributed binary, the flag was displayed when I ran the command as described in the problem statement.スクリーンショット 2022-03-18 0.57.05.png

patchme.py (100pts)

When I run the distributed python file, it asks for Please enter correct password fo flag:. If you look at the contents of the file

    if( user_pw == "ak98" + \\
                   "-=90" + \\
                   "adfjhgj321" + \\

Since there is a notation that , you can get a flag by entering ak98-=90adfjhgj321sleuth9000 as pw.

Safe Opener (100pts)

The distributed Java file contains

String encodedkey = "cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz";

and in the SafeOpener class

Base64.Encoder encoder = Base64.getEncoder();

You can also see the notation that says. Apparently, it compares the input encoded by b64 with the encodedkey, so I decoded it and it became pl3as3_l3t_m3_1nt0_th3_saf3. This is enclosed in picoCTF{} and is a flag.

unpackme.py (100pts)

Insert print(plain) between the plain = f.decrypt(payload) and exec(plain.decode()) of the unpackme.py to see what is running in the exec(). When I ran it, it contained a flag in the plain.

bloat.py (100pts)

When I run the distributed python file It is said that it is Please enter correct password for flag:. The contents are subtly obfuscated and frustrating, but apparently

if arg432 == a[71]+a[64]+a[79]+a[79]+a[88]+a[66]+a[71]+a[64]+a[77]+a[66]+a[68]:

It seems to be judging the password in the part. So, if you insert print(a[71]+a[64]+a[79]+a[79]+a[88]+a[66]+a[71]+a[64]+a[77]+a[66]+a[68]) at an appropriate position and display the contents, you can see that this value is happychance. After that, the flag is displayed by entering this value again.

Fresh Java (200pts)

Reverses binaries distributed using Java's decompiler. I use Docker

% docker run -it --rm -v $PWD:/mnt kwart/jd-cli /mnt/KeygenMe.class > decode.java

Got the reverse result as: Looking at the contents,

if (str.charAt(2) != 'c') {
  System.out.println("Invalid key");
if (str.charAt(1) != 'i') {
  System.out.println("Invalid key");
if (str.charAt(0) != 'p') {
  System.out.println("Invalid key");

and the flags are compared to the correct answer letter by character, so you can get the flag by connecting them.

Bbbbloat (300pts)

I was asked to run the given Binary and was told What's my favorite number? if I put in the appropriate numbers, it would be Sorry, that's not it!. I decompiled Binary with Ghidra

printf("What\\'s my favorite number? ");
if (local_48 == 0x86187) {
  __s = (char *)FUN_00101249(0,&local_38);
else {
  puts("Sorry, that\\'s not it!");

Since I saw the result, I entered 549255 (=0x86187) and the flag was displayed.

Web Exploitation

Includes (100pts)

The first half of the flag was written in the style.css of the web page, and the second half was written in the script.js. スクリーンショット 2022-03-20 18.00.54.png スクリーンショット 2022-03-20 18.00.56.png

Inspect HTML (100pts)

Flags are listed in the comments in the HTML file of the web page.スクリーンショット 2022-03-20 18.05.12.png

Local Authority (100pts)

The login form was displayed, so when I logged in with the appropriate ID and PW, I was skipped to the login.php. On this page, we are reading a file called secure.js, and its contents are

function checkPassword(username, password)
  if( username === 'admin' && password === 'strongPassword098765' )
    return true;
    return false;

Because it is a fierce yaba implementation, when I logged in again with this id and pw, the flag was displayed.

Search source (100pts)

Essentially, it's no different from Includes, but it's hard to look for it with your eyes because of the amount of sentences. At first

% wget -r http://saturn.picoctf.net:58133/

As a web page to keep at hand. By adding -r options, you can save links such as js and css at the same time. Continued

% grep -rl pico

Locate the file that contains the string pico as. Apparently the ./saturn.picoctf.net:58133/css/style.css contains flags. At last

% cat ./saturn.picoctf.net:58133/css/style.css | grep pico
/** banner_main picoCTF{1nsp3ti0n_0f_w3bpag3s_587d12b8} **/

Get flagged as:

Forbidden Paths (200pts)

Enter ../../../../flag.txt as Filename to display the flag.

Power Cookie (200pts)

Since a cookie called isAdmin: 0 is set, I changed it to 1 and the flag was displayed.スクリーンショット 2022-03-20 16.04.07.png

A Chrome extension called EditThisCookie is useful for rewriting cookies.

Secrets (200pts)

Since it says We have several pages hidden. in the problem statement, there is probably a page that is not linked. Use the DIRB to run Brute Force.

% dirb http://saturn.picoctf.net:61481/

DIRB v2.22    
By The Dark Raver

START_TIME: Sun Mar 20 07:40:05 2022
URL_BASE: http://saturn.picoctf.net:61481/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt


GENERATED WORDS: 4612                                                          

---- Scanning URL: http://saturn.picoctf.net:61481/ ----
+ http://saturn.picoctf.net:61481/index.html (CODE:200|SIZE:1023)              
==> DIRECTORY: http://saturn.picoctf.net:61481/secret/                         
---- Entering directory: http://saturn.picoctf.net:61481/secret/ ----
==> DIRECTORY: http://saturn.picoctf.net:61481/secret/assets/                  
==> DIRECTORY: http://saturn.picoctf.net:61481/secret/hidden/                  
+ http://saturn.picoctf.net:61481/secret/index.html (CODE:200|SIZE:468)        
---- Entering directory: http://saturn.picoctf.net:61481/secret/assets/ ----
---- Entering directory: http://saturn.picoctf.net:61481/secret/hidden/ ----
+ http://saturn.picoctf.net:61481/secret/hidden/index.html (CODE:200|SIZE:2118)
END_TIME: Sun Mar 20 08:39:18 2022

drib found a page called http://saturn.picoctf.net:61481/secret/hidden/index.html. I'll try to access it because it's kind of like that. Then you can see that it is loading a resource called http://saturn.picoctf.net:61481/secret/hidden/superhidden/login.css. So I went to http://saturn.picoctf.net:61481/secret/hidden/superhidden/ and found a flag in the page with the same color as the background.

SQL Direct (200pts)

Connects to the specified SQL server, examines the table list, and displays the contents of the table.

pico=# \\dt
         List of relations
 Schema | Name  | Type  |  Owner   
 public | flags | table | postgres
(1 row)

pico=# select * from flags;
 id | firstname | lastname  |                address                 
  1 | Luke      | Skywalker | picoCTF{L3arN_S0m3_5qL_t0d4Y_31fd14c0}
  2 | Leia      | Organa    | Alderaan
  3 | Han       | Solo      | Corellia
(3 rows)

SQLiLite (300pts)

You can log in by setting the appropriate value for pw with Username as the ' or 1=1 ;-- . Also, when I looked at the page in the developer tools, it was flagged.

Author by

( ; ; ) ← 無限ループに泣かされている人の顔文字です。

Updated on April 06, 2022