1 ## The CTF in retrospective
3 It was the first time I saw a Jeopardy CTF so I can't compare it with others. However I think it was fun and challenging. Just like I immagined it. I tired to pick challenges that contained something somehow familiar.
4 I wasn't successful in solving them and I am impressed of how satisfying it is to look at others solutions afterwards and understand what I did not think of.
6 ## Option-Cmd-U (not solved)
8 The first thing I did was letting the Browser show me the HTML document. There I found the comments that describe how the challenge works.
10 <!-- src of this PHP script: /index.php?action=source -->
11 <!-- the flag is in /flag.php, which permits access only from internal network :-) -->
12 <!-- this service is running on php-fpm and nginx. see /docker-compose.yml -->
14 `/index.php?action=source` then revealed the PHP code:
17 if (isset($_GET['url'])){
18 $url = filter_input(INPUT_GET, 'url');
19 $parsed_url = parse_url($url);
20 if($parsed_url["scheme"] !== "http"){
21 // only http: should be allowed.
22 echo 'URL should start with http!';
23 } else if (gethostbyname(idn_to_ascii($parsed_url["host"], 0, INTL_IDNA_VARIANT_UTS46)) === gethostbyname("nginx")) {
24 // local access to nginx from php-fpm should be blocked.
25 echo 'Oops, are you a robot or an attacker?';
27 // file_get_contents needs idn_to_ascii(): https://stackoverflow.com/questions/40663425/
28 highlight_string(file_get_contents(idn_to_ascii($url, 0, INTL_IDNA_VARIANT_UTS46),
30 stream_context_create(array(
32 'follow_location' => false,
39 ` filter_input(INPUT_GET, 'url')` according to the documentation does noting: "Do nothing, optionally strip or encode special characters."
40 ` parse_url($url)` parses the url into an associative array. The array then contains the parts of the url (scheme, host, port, user, pass, etc).
41 `idn_to_ascii` converts a unicode domain into an ascii domain.
42 The PHP code checks if the entered URL has the scheme `http`. If this is the case, it checks if the ip of the host in the url is the same as the ip of `nginx`. The host `nginx` is available in the docker network for the inter container communication.
44 Then I tried to access `flag.php`. I got an error message containing my ip. So i copied the link into the input filed of the index.php and it showed the same error message but with the ip `172.25.0.1`. I tried to enter `http://127.0.0.1:10000/flag.php`. That returned an error "Connection refused". So it can't be the ip of the nginx server. Therefore php-fpm and nginx must run in different containers. A look at the /docker-compose.yml confirmed this. So its the ip of the php-fpm container in the docker network. By trying to enter `http://172.25.0.2/flag.php` and `http://172.25.0.3/flag.php` I found out that the ip of the nginx container is `172.25.0.3` (because it shows "Oops, are you a robot or an attacker?")
46 By looking closer at the PHP code I saw, that the `if` that was preventing me from accessing the `flag.php` uses `$parsed_url["host"]` while the method I would want to invoke uses `$url`. According to the PHP documentation `parse_url($url)` will replace invalid characters with `_`. So if I find a character that is invalid for `parse_url` but not for `ind_to_ascii` or I will find a url form that causes `parse_url` to choose a wrong host i could acces the flag.
47 I've set up a small test setup to be able to test the different urls and see which method returned what. The best I got was a `#` or a whitespace in the url but that caused the schema to be non http. [Maybe I am about three years to late.](https://bugs.php.net/bug.php?id=73192)
49 While I was trying somebody of our team solved the challenge and I did not continue.
51 ## Sandstorm (not solved)
53 ![sandstorm.png](https://gitlab.w0y.at/ctf-seminar/ws19/raw/master/writeups/matthias/seccon2019/sandstorm.png)
56 - check if the Image contains any `exif` information
57 - `Stegsolve.jar` to see if something is written on the image
58 - `string` to check if there is a valid string in the image file that could be the flag
61 Then I converted the image into a txt containing the rgb color values: `convert sandstorm.png :-txt `. I found out, that there are 2202 pixels which are not black or white. So I turned the black pixels into white ones and generated a new image:
63 ![newimage.png](https://gitlab.w0y.at/ctf-seminar/ws19/raw/master/writeups/matthias/seccon2019/newimage.png)
66 I saw that the pixels that are not black or white contained three times the same value followed by FF (e.g. F6F6F6FF). So I tried to take the first value of every pixel, treat it as binary combine them in an array and turn it into a string.
68 public static void main(String[] args) throws IOException {
69 File f = new File(PATH_TO_TEXT_FILE_REPRESENTING_THE_IMAGE_WITHOUT_BLACK_AND_WHITE_PIXELS);
70 BufferedReader bufferedReader = new BufferedReader(new FileReader(f));
72 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
73 while((s = bufferedReader.readLine()) != null) {
74 int pos = s.indexOf("#");
75 s = s.substring(pos+1,pos+3);
76 byteArrayOutputStream.write(hexToByte(s));
78 System.out.println(new String(byteArrayOutputStream.toByteArray(),"UTF-8"));
81 public static byte hexToByte(String hexString) {
82 int firstDigit = toDigit(hexString.charAt(0));
83 int secondDigit = toDigit(hexString.charAt(1));
84 return (byte) ((firstDigit << 4) + secondDigit);
87 private static int toDigit(char hexChar) {
88 int digit = Character.digit(hexChar, 16);
90 throw new IllegalArgumentException(
91 "Invalid Hexadecimal Character: " + hexChar);
96 But without luck. At this point i had no more ideas of how to get a flag out of the image and I surrendered.