]> git.somenet.org - pub/jan/ctf-seminar.git/blob - writeups/matthias/seccon19.md
phager
[pub/jan/ctf-seminar.git] / writeups / matthias / seccon19.md
1 ## The CTF in retrospective
2 ---
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.
5
6 ## Option-Cmd-U (not solved)
7 ---
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.
9 ```html
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 -->
13 ```
14 `/index.php?action=source` then revealed the PHP code:
15
16 ```php
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?';
26     } else {
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),
29                                            false,
30                                            stream_context_create(array(
31                                                'http' => array(
32                                                    'follow_location' => false,
33                                                    'timeout' => 2
34                                                )
35                                            ))));
36     }
37 }
38 ```
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.
43
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?") 
45
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)
48
49 While I was trying somebody of our team solved the challenge and I did not continue.
50
51 ## Sandstorm (not solved)
52 ---
53 ![sandstorm.png](https://gitlab.w0y.at/ctf-seminar/ws19/raw/master/writeups/matthias/seccon2019/sandstorm.png)
54
55 What I tried:
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 
59
60 Nothing was helpful.
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:
62
63 ![newimage.png](https://gitlab.w0y.at/ctf-seminar/ws19/raw/master/writeups/matthias/seccon2019/newimage.png)
64
65 So not helpful too.
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.
67 ```java
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));
71     String s = "";
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));
77     }
78     System.out.println(new String(byteArrayOutputStream.toByteArray(),"UTF-8"));
79 }
80
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);
85 }
86
87 private static int toDigit(char hexChar) {
88     int digit = Character.digit(hexChar, 16);
89     if (digit == -1) {
90         throw new IllegalArgumentException(
91                 "Invalid Hexadecimal Character: " + hexChar);
92     }
93     return digit;
94 }
95 ```
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.
97
98