Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
This is where we post our writeups for CTF challs!
Add
bam ez flag
Clone git repo
Git clone
Find the commit logs at /.git/logs/HEAD
Get the Sha-1 hash of the first log
Git checkout 6b3c94c0b90a897f246f0f32dec3f5fd3e40abb5
(Switches to that version of the repo)
Cat thisistheflag.txt
actf{b3_car3ful_wh4t_y0u_s3rve_wi7h}
Use r2 to find address of flag function, 0x00401186
Find buffer length needed.
This will give you an exact timestamp and an approximate PID Next run following command locally, with a flag.txt file of length 49
You will get a number of different outputs Look for one that has the last letter of flag.txt xor'ed in the same place as the } xor'ed was on the shell Dexor Reassemble the flag GG;No re
Have a bit of an experiment The input is broken down into 4 chunks of 8 Imagine the output like a grid The first character is converted to binary and written to the grid like a diagonal line, with the lsb at the top. For the next character the line is shifted to the right one, and so on until all characters in the chunk have been written. This repeats for the next 3 chunks, except instead of 1, the numbers 2, 4 and 8 are written instead After the string is written 40 is added to all squares and it is converted to ascii. To solve, unconvert, subtract 40 and reverse the process gg, beat woak
All we had to find was a'/a and apply it on b'wb to get a'b'wba to get our solution but reversing it to achieve fewest moves. i did a'waw' to find the differences between the 2 scrambles. luckily only corners were affected so i can take less time. i then analysed the movement of corners swaps of w and represented them in Old Pochmann notation: ANTXPDGJ afterwards i mapped out the corner swaps of a'wa also represented in Old Pochmann notation: AMPHFNLO then i got a sheet of paper and mapped out a'wa corner pieces onto the corner swaps of w to find the setup move (a = B U B U D' F' L2 F U2 L2 U' L2 D F2 U2 F2 U' B2)
. After filling the cube corners out i plugged it into the rubiks cube solver to get a. i applied it onto b'wb and then plug it into the rubiks cube solver again and reverse the solution to get the flag.
http.request.method == GET on wireshark
Export Objects > HTTP > git-receive-pack
Create a new git repo
Place in the git repo
Open in hex editor and fix the file header to be just 'PACK' at the beginning (remove all the crap)
Now git unpack-objects < git-receive-pack
Navigate to objects folder, here there are 3 git objects:
a commit
a tree file
a blob file
Decompress the zlib blob file with: python -c "import zlib; print zlib.decompress(open('3f47cbcb3ad8e946d0aad59259bdb1bc9e63f2').read());" > flag.jpg
Open the file up in a hex editor and remove the first few bytes so the header is a jpeg header
Open it up for the flag
actf{git_good_git_wireshark-123323}
Found this repl.it on this stack overflow, adjusted to this and used x function to manually calculate values
Report that, bam ez
Use pattern.py to flood the second input, put a breakpoint at the line in greet which compares the canaries. Check rax using gdb, feed that back into pattern.py, 56 bytes before canary. Fuzz format string output until you find the one that's always 8 bytes long, that's the canary Make a script that leaks the canary then overflows the buffer with 56 junk bytes + canary + 8 junk bytes + flag address
So i averaged the first 10 nums and gave it a number as well as add 0.5 (to reverse what the source did) this gave me binary and i replaced it with values from source. i shoved it into a morse code decoder to get a pattern and then brute forced the flag by guessing what the letters could be
Found arguments were 3 numbers 0-9 and "chicken" Although not meant to I brute forced it with this python script:
String "ZFOKYO\nMC\O\nLFKM"
seen in memory About where the password is compared XOR it with the key 2a to get 'please give flag' with newlines removed.
Deobfuscate all the code and after finding this line
This sends a post that'll send mouse coords. after i messed around a bit i realised that the shapes coords are different from the one they send to you so i guess something happens with them (not sure what tho). i then analysed the thingies going on in network which was always in the pattern start [get shapes, send coords, get score] and found the code to find mouse coords (see deobfuscated js) was consistent with where the shapes are displayed. after that i looked at the code that draws out the shapes with the coord and figured out how it knows whether to draw a circle or square. which was:
If you know a little js, it chooses the first element of the shapes list to be a circle and the rest are squares. after that i checked whether the shapes list matches the shapes list going in through the network and found they were different. The shapes list was correct and matched the coords of the circle and after analysing a thingy that sends my mouse coords, they were roughly the same which meant i could create the payload
Spam it through console when i press start which gave me points :) and then i got the flag (turns out i didnt need the backend source code lol)
Open program in cutter and disassemble main
Looking at "linux 7 signal" - we see a load, so I bruteforced them all until one worked - found it was SIGABRT
This means that we need to kill the program , or abort it Spinning it up on the shell, we have to do
Which gives up the PID of the program and then runs it Open up a new shell, and do "kill -6 PID"
Bam!
The binary prints the address of our input, then uses read to read input into it. There's 16 bytes of buffer overflow, letting us overwrite rbp and the return address only. As NX is off and our input is on the stack, we can just set the return address to our input, and then put shellcode in our input. After popping a shell, we cat flag.txt to get the flag.
The binary comes with a libc and ld. As the title, description and even text of the binary suggests, the libc is patched. I patched the ELF file so that it would always run with this ld and libc, even on my local end.
The binary prints some stuff using puts, calls printf("> ") and then calls gets on rbp-0x80.
This creates a buffer overflow. With NX on this time, it'll be a little more difficult. We can execute a classic ret2plt attack, retting into puts@plt(no PIE) to print out puts@got, creating a libc leak. Things are a little harder as the libc is patched. There's no /bin/sh in it, presumably the system doesn't work properly. We talked about this in the Statics and Dynamics writeup from HacktivityCon CTF - with so much code, libc is a ROP gadget gold mine. So once we've used ret2plt to leak the libc base, we can just use ROP to build a chain that uses syscalls to pop a shell.
Note that due to stack alignment we'll need to use a return gadget before returning back into main, and also I chose the instruction at 0x40123c(which is part of main) for convenience.
We can use the pwntools ROP functionality to build a nice and simple ROP chain that reads data into a writeable section, then uses execve(execve(section,NULL,NULL) specifically). Afterwards, we'll send /bin/sh which will get written to said writeable section, thus the total payload will pop a shell.
We're provided with a download of the VScode source code, slightly modified. The name hinted at a patch happening, so I ran git diff
and found a 'backdoor' leading to congonator.me/?id=ZmxhZ3tkb250X3RydXN0X2RvZGd5X2Rvd25sb2Fkc30%3D&key= when a key was pressed. I just decoded the id
paramater, which revealed the flag.
Run script then profit
Now we didn't actually solve this, due to instability with the challenge. But we came up with a script that seemed to be working well before the instance died:
We simply need to unswirl this image, using a site such as https://www.photo-kako.com/en/swirl.cgi
I personally used an angle of 900% which gave me the flag perfectly readably.
legit cat the file cyber chef go brrr
So you have an ez bake oven, go to the cookies tab and start baking.
after this, decode the base 64 of the cookie, and then edit it to a date that has passed over 5 days ago, make sure to use mm/dd/yyyy format, then base64 encode this, and then change the cookie for the site to your new base64 encoded cookie.
/src.php has source for the site. We can send a few params, which are hashed together and the result (chars 5-25) are compared to '0' (using ==
). In php, this is vulnerable to type juggling. 0e1434 == '0'
for example. We simply have to find a set of values satisfying these constraints.
curl http://challenge.ctf.games:31965/index.php -d 'name=test&answer=6b067ebdb712e42e64e6dcaeb6513afd0f801bfc&time=12345678901'
Python Deserialization Vulnerability, https://xerosecurity.com/wordpress/exploiting-python-deserialization-vulnerabilities/
bruteforce X using m counting down
So the encryption calculates x^3 + ax + b mod p. Initially, we don't know a, b, or p, but we can encrypt arbitrary messages and get the encryption of the flag.
So, how do we leak values with this? First of all, we encrypt 0 - the equation will equate to b.
Next, we encrypt 1 - the equation will be 1 + a + b, so subtract b and subtract 1 to get a, or some value that equates to a mod p.
Finally, we must leak p. This is simple, continue encrypting small messages and also encrypting them ourselves with the calculated a and b values. Eventually, we'll find that our calculated value is different to the value returned - from there, we work out the modulus that would require both of the values to be equal. In my case, my calculated value was negative and the value returned by the server was positive so adding the absolute values returned the modulus.
This gives us the equation x^3 + ax + b mod p = c where we know a,b, and c. From there I got maf slave rak to solve the equation using sage :P
No script because I did it all manually in a python prompt but here have my PoW solver
Blind sql
It gives 248b57c5cabbc9944d169d10bc4959a042d0bb81ab6cfc9166f40a9d0f0fd614 which is hash of "tigers"
Download /bart
Run strings to get b64 string
Decrypt
Get flag
You can inspect packets using tcpdump and find the domain covidfunds.net, OR you can step through the program in the debugger, notice the string Y292aWRmdW5kcy5uZXQ=
getting base64 decoded, base64 decode it yourself and you will find it decodes to covidfunds.net
We can run a "chosen plaintext" attack on the server. It takes our input, then calculates encrypt(input + flag). Because ECB encrypts each block separately and simply concatenates them, we can brute force the flag byte by byte. A block is 16 bytes. Say if we gave the server 15 As, This means that the first block of the response is the ECB encryption of 15 As + the first byte of the flag. We'll call this block k1.
If we continuously send 15 As + and then compare the first block, then the byte in which the first block of the encryption is equal to k1 is the first byte of the flag.
If we send 14 As, the first block is the encryption of 14As plus the first two bytes of the flag. Given the first byte of the flag, we can run a similar brute force. This continues for the first block, the second block, and however many blocks there are until the flag finishes.
After looking up sqlite formats i made the payload
To get all table names and then
To get the settings of that table. the flag was 58
Chuck it in ghidra or your favourite decompiler/analyser - we see it prints the system address to us, then uses gets to read an input. This is a classic buffer overflow which we'll attack with ret2libc.
As it prints the libc address of system, we can simply use that to calculate the libc base. The binary is 32-bit, and it reads input into ebp-0x1c, giving 32 bytes of padding until return address overwrite. Then, we just send system + junk + /bin/sh address
Note that we don't know the remote libc - I used libc-database find to get the remote libc binary, which is libc6_2.30-0ubuntu2_i386
So: 1. Receive libc address 2. Calculate libc base 3. Build ret2libc system("/bin/sh") chain 4. Pop shell, cat flag.txt
The binary has no protections except Partial RELRO.
The menu has 3 options besides exiting, one of which is secret.
We can read into a shellcode pointer, but only 5 bytes get read. We can execute said shellcode. This is all pretty much useless since 5 bytes of shellcode is not enough to do literally anything useful.
There's a secret option - gomugomunomi. It reads 100 bytes of input(no BOF) and then printfs it, allowing us to execute the classic format string exploit.
I tried to do the simple %p leak, but found no useful addresses on the stack. Instead, I used %s to read my buffer(offset 7, found through pwntools automation) as an address of a string in order to read got entries.
By doing gotaddress + %7$s we can leak got addresses to get a libc leak. We'll use libc-database find yet again to get the remote libc, libc6_2.30-0ubuntu2.2_i386
Then, we'll execute a got overwrite attack by overwriting printf@got with system. Next gomugomunomi, the input will be system'd, so we enter /bin/sh to get dropped into a shell.
But it's not over! On the remote, there is no cat. The solution to read flag.txt is simple - while read line; do echo $line; done < flag.txt
This reveals the flag.
gotaddress+ %7$s to leak libc
Format string overwrite to map printf to system
In gomugomunomi, send /bin/sh
Use while read line; do echo $line; done to read the flag file as cat is nonexistent
If you request the sums of 0 1, 1 2, and 2 0, you can sum them and divide to get the sum of 0, 1 and 2.
Then subtracting one of the above from this lets you find 0, 1 and 2, from which you can ask for 2 3 to get 3, etc.
Script below.
https://github.com/tna0y/Python-random-module-cracker
(title hints at mersenne twister, which is what python random uses)
script below:
We are only allowed to use these characters: $()_[]=+;".
Webserver evals our input.
We also have a 2000 character cap (found by experimenting)
Found a pretty good resource on this: https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
Main idea is to
use underscores for variables names
use $_=([]."")[([]==[])+([]==[])+([]==[])]
to get a lowercase a
use $_=([]."")[[].[]+[][[]]]
to get an uppercase A
use [varname]++
to increase the ascii value for each of these to get all ascii letters
take a string and join our characters one by one with .=
for other characters, we can just join then with .="char"
, assuming it is allowed.
Our first goal is to get phpinfo, to see if there are any disabled functions:
Payload:
We can see that useful functions which would have allowed us to read from the file like file_get_contents are disabled. However, readfile() is not disabled, so we can use that. We can then use printf() to output that to us.
Our final payload will then eval to: printf(readfile("FLAG.PHP"))
Final payload:
(need to view source to see it)
Numbers
The program is a constant prompt that... 1. Reads a number from us 2. Checks if the number is greater than 60, if so it tells us we're naughty and exits 3. Reads that amount of data into a 64 length buffer 4. Prints the data 5. Asks if we want to try again, just dont type n
There's also some prompts inbetween but those aren't important. At first glance, this seems perfectly secure. But actually, note this code snippet.
It actually uses atoi to convert our input to a number, and atoi allows signed integers.
This means we can enter a negative number, like -1, and atoi will return 0xffffffff
the read function takes a size_t parameter - it wont think we're trying to read -1 bytes of data, but 4294967295
bytes of data. Now that's a lot of overflow.
PIE is on, so we cant just overwrite the return address of the integer reading function, ret2plt and call it a day. Because it prints our input back at us, we can exploit it similarly to skywriting from redpwn.
As a recap, strings are terminated by null bytes. When a function, like printf in this case, attempts to print a string, it will continue reading data until it reaches a null byte, at which it will stop.
If we make our input long enough, overwriting null bytes and nudging itself next to some data, said data can be leaked. Imagine it like this:
(our input is at the beginning, and we wish to leak the 0xdeadbeef data) currently this reads as an empty string let's fill the input with AAAA
Now, the null bytes have been overwritten, so the 0xdeadbeef is part of the string! This reads to be AAAA\xde\ad\be\ef.
8 bytes from the beginning of our buffer is atoi+16, we can leak this using this method and calculate the libc base. Our input is 72 bytes from the return address, so after leaking we will send 72 bytes of padding + poprdi + /bin/sh + retgadget(stack alignment) + system to overwrite the return address of the buffer reading function and pop a shell.
Then, cat flag.txt
to get the flag.
Send size of -1 to gain large buffer overflow
Send 8 bytes to leak libc address(atoi+16)
Use libc-database find to get the remote libc(libc6_2.28-0ubuntu1_amd64)
Use size -1 trick again to overwrite return address and send system("/bin/sh") rop chain to pop a shell
Looking at the script, it scrambles the flag (by using one of the flag's characters as the seed), splits it into blocks of 2 bytes, and then pads them, and then AES encrypts them with a known key.
We start by decrypting each block with the key to get a long string: aaFho_i_aC2b_abfc8edFw!kolae_ngbom_r__f_9T525eg__ihedd}{pmertt
Then, we bruteforce the seed by trying each of the characters of the flag as the seed. We do this by scrambling our own string (I chose ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
) with the seed, and then comparing it to the above string and see if it's in flag format.
Seeing as "w" only appears once, and it is in the flag format, I based my check on this. We check if our output string[21] is equal to "B", since this is its place in the flag format.
We get our seed as "h", and we encrypt our string with it. Last thing to do is to match each character up to its original position. Script below:
Whatever we input, the binary searches for characters in our input that are the same as a character of the flag in the same position. It prints the number of characters before the first occurrence of this. For example, if the flag was FwordCTF{}, then...
Fgjehrfd -> 0
sws -> 1
gggg -> 4
Using this, we can run a simple byte by byte bruteforce in order to get the data in flag.txt - NuL1_Byt35?15_IT_the_END?Why_i_c4nT_h4ndl3_That!}
Adding the flag format, we get the flag, FwordCTF{NuL1_Byt35?15_IT_the_END?Why_i_c4nT_h4ndl3_That!}
I used backticks for padding since they were pretty much guaranteed not to be in the flag - we can send backtick_padding + char and bruteforce "char" until the number returned equals the number of backticks, the character of the flag in that position would be the char where the server returned number is equal to the number of backticks.
Basically, there is an LCG being used to generate the string of numbers. It takes a seed, multiplies it with "a", adds "b", and then takes that mod a prime "p".
We don't know any of these values however. It generates a list of numbers from a starting random seed this way, and then xors each character of the flag to get a new list.
We know the flag format is "FwordCTF{"
, so we can start by XORing these characters to get the actual string of LCG generated numbers: [6680465291011788181, 5100570103593250306, 5906808313299165163, 1965917782737693404, 9056785591048864532, 1829758495155458643, 6790868899161600099, 1596515234863242753, 1542626304251881944]
Now, we do some modular maths stuff:
6680465291011788181 a + b = 5100570103593250306 5906808313299165163 a + b = 1965917782737693404(all of these are taken mod p of course) 1596515234863242753 * a + b = 154262630425188194
We can subtract the equations from each other to get rid of the b: (6680465291011788181 - 5906808313299165163)a = 5100570103593250306 - 1965917782737693404 (5906808313299165163 - 1596515234863242753)a = 1965917782737693404 - 1542626304251881944
Simplifying:
Im using these from now because idk why the others arent working
Solve script:
Here's what the program does
First of all, use a mess function to encode the flag. This mess function is easily byte by byte bruteforceable if we use the printable range of characters.
Let's call this mflag.
Next, it pads the mflag so that it's length is a multiple of 9 using .
Then, it encrypts the mflag using matrix multiplication. Splitting the mflag into bunches of 9, it fills up a 3x3 matrix using the ascii values, multiplies it by a key that we know, transposes the resulting matrix, and turns it into a string result of of form
This is all done using the messig_up function. Then, it takes the output, parses it, and uses an encode function to encode each of the numbers, writing them all to the output file. I didn't reverse the encode function, and instead just did a classic bruteforce to get the numbers which were all less than 2500.
Here's how the solve script operates.
Create a mapping of all possible encodings. Now, decode all the number encodings using this mapping.
Split the numbers into groups of 9, fill up 3x3 matrices, and transpose these matrices to get the pure matrix multiplication outputs.
Calculate the matrix inverse of the matrix key, then multiply the matrices by this inverse to get the original matrices
String together all these matrices back into a string by taking the ascii values(we call round, as the results will be floats) to get mess(flag)
Use our byte by byte bruteforce mess function to decode the messed flag.
Script below:
Each character of the plaintext is encrypted using a known N and unknown e, creating a ciphertext array we're given. Infact, the actual RSA behind it is completely irrelevant. All we need to know is that each character is mapped to a number via a mapping function which we cannot reverse. The ciphertext is 932 numbers long, with 31 unique numbers, making it the equivalent of a simple substitution cipher which we can easily break using frequency analysis.
I used this script(with the values already loaded in enc)
Which prints out:
I'm not sure why the output is wrong, but it can be chucked into a substitution cipher solver(https://www.guballa.de/substitution-solver) to get the real plaintext:
From here we can see the flag is WELLFREQUENCYANALYSISROCKS wrapped in the flag format(you actually had to put it in lowercase too)