news 2026/9/12 21:51:43

bugku-awd-3s-6

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
bugku-awd-3s-6

bugku-awd-3s-6

一、MySQL 3306 对外 + cms 固定弱口令 + ALL PRIVILEGES(根因)

漏洞类型

数据库弱口令 + 权限配置不当。这场最致命的一个,赛后复盘才彻底搞明白。

形成原因

所有靶机的core/config.php里,MySQL 密码是同一个固定值eb0d39d2931c480f,而且cms用户是cms@'%'——任意主机都能连,权限还是ALL PRIVILEGES ON *.* WITH GRANT OPTION。MySQL 又开了bind_address=*,3306 端口直接暴露在公网。换句话说:知道这个固定密码的人,就能直连的我们数据库干任何事。

14:40 对手就是这么打进来的:直连 3306 →SET GLOBAL general_log把 webshell 写到/var/www/html/cache/sh96.php→ 顺手把mimelist改成放行 .php → 再改掉 admin 密码 → 14:59 用改后的密码登后台传了第二个 webshell。一开始还以为是 Web 注入,后来翻日志、看文件 owner(是mysql:mysql)才确认是直连数据库。

原代码截图

源码

<?php/* 数据库配置 */$_L['mysql']['host']="127.0.0.1";$_L['mysql']['port']=3306;$_L['mysql']['user']="cms";$_L['mysql']['pass']="eb0d39d2931c480f";// ← 第 6 行,固定弱口令$_L['mysql']['name']="cms";$_L['mysql']['pre']="lcms_";$_L['mysql']['charset']="utf8mb4";

修改后的代码

config.php同步成新密码(fix_mysql.py干的活):

$_L['mysql']['pass']="cms_Awd_2026#Xy9k";

数据库侧两步(fix_mysql.py+ 漏洞总结 13.3):

-- 1. 改 cms 密码,让旧固定密码失效ALTERUSER'cms'@'%'IDENTIFIEDBY'cms_Awd_2026#Xy9k';FLUSHPRIVILEGES;-- 2. 收紧权限:就算再被直连,也写不了文件、改不了全局变量REVOKESUPER,FILE,GRANTOPTIONON*.*FROM'cms'@'%';

小记:bind_address=*其实改不掉(要 root 重启 mysqld,我们没 root),所以只能靠「改密码 + 收权限」兜住。改完我用旧密码试连,已经进不去了,web 功能也正常,才放下心。


二、index.php 一句话后门

漏洞类型

Webshell 后门 / 远程命令执行(RCE)

形成原因

靶机根目录index.php第一行就躺着一句话木马,谁 POST 个a参数都能执行任意 PHP 代码。


三、upload 目录一句话木马

漏洞类型

Webshell 后门 / 远程命令执行(RCE)

形成原因

upload目录里还藏了一个一句话木马,文件名是随机的(看着像 base64),POSTaaa就能 RCE。

复现(Burp Suite):

  1. 同样把请求丢进Repeater,请求行改成POST /upload/0/file/202210/TYZMTYNTIxMzYMTAODcOQ.php HTTP/1.1
  2. Body 填aaa=system('cat /flag');
  3. Go,响应里直接回显/flag内容,跟上面 index.php 那个一样好使。

四、后台弱口令 admin/admin + 4 位数字验证码

漏洞类型

弱口令 / 验证码可爆破

形成原因

后台超级管理员是admin,密码存的是 MD5,而且就是MD5("admin")。验证码更坑:4 位纯数字(randstr(4,"num"),存 sessionLCMSPINCODE),输错还不重置——意味着对着同一张验证码能把 0000~9999 全爆一遍。

对手 14:59 那波就是这么干的:先用改后的密码登后台,验证码暴力过掉,然后走 upload 传了第二个 webshell。

原代码截图

源码

-- lcms_admin 表里的 admin 行INSERTINTO`lcms_admin`VALUES(1,0,1,'admin','超级管理员','21232f297a57a5a743894a0e4a801fc3',...);-- 21232f297a57a5a743894a0e4a801fc3 = MD5("admin")

修改后的代码

改密码(比赛里fix_upload_attack.py先把被篡改的密码恢复成原强密码,赛后应该再设一个更复杂的):

UPDATElcms_adminSETpass='a7fa6b25198e06dbb5c40dae058bd283'WHEREname='admin';

五、login docheck SQL 注入(登录绕过)

漏洞类型

SQL 注入(字符串拼接,admin 模块 filterform 完全不过滤)

形成原因

登录校验的docheck()里,查询是拿str_replace:name占位符替换进 where 子句的,本质还是字符串拼接,name参数没做任何过滤。所以:

name=' OR '1'='1' --pass=1

就能直接绕过去。而且 admin 模块的filterform完全不过滤,union select 都能回显,配合验证码爆破基本等于白给。

原代码截图

源码

publicfunctiondocheck(){global$_L,$CFGA;...$pass=md5($_L['form']['pass']);$admininfo=sql_get(["admin","(name = ':name' OR email = ':name' OR mobile = ':name') AND pass = '{$pass}'","id DESC",[":name"=>$_L['form']['name'],// ← 没过滤就直接替换进 SQL]]);

修改后的代码

name加了个addslashesdeploy_waf.py里顺手改的):

$pass=md5($_L['form']['pass']);$name=addslashes($_L['form']['name']);$admininfo=sql_get(["admin","(name = ':name' OR email = ':name' OR mobile = ':name') AND pass = '{$pass}'","id DESC",[":name"=>$name,]]);

六、后台登录绕过(n=login 重复参数)

漏洞类型

认证绕过(参数解析不一致)

形成原因

这个藏得挺深。check_login()判断「是不是登录页」用的是HTTP_QUERY(整个 REQUEST_URI 的子串匹配),而真正要加载的模块名L_NAME是从$_GET['n']取的——PHP 对重复参数取的是最后一个。所以 URL 里先放个n=login骗过匹配,再放真实模块名,就能不登录直接进任意后台模块:

/admin/index.php?n=login&n=backup&c=database&a=index

当时用这个思路去访问 backup / user / config 等模块,配合后台的注入点就能打。

原代码截图

源码

protectedfunctioncheck_login(){global$_L;$_L['LCMSADMIN']=SESSION::get("LCMSADMIN");$loginrootid=SESSION::get("LCMSLOGINROOTID");if(stristr(HTTP_QUERY,"n=login")===false&&!$_L['LCMSADMIN']){// ← 第 54 行:拿 REQUEST_URI 子串判断,能骗okinfo("{$_L['url']['admin']}index.php?rootid={$loginrootid}&n=login&go=".urlencode($_L['url']['now']));}elseif($_L['LCMSADMIN']){

修改后的代码

改成只看真实加载的模块名L_NAMEfix_login_bypass.py),重复参数这招就废了:

if(L_NAME!="login"&&!$_L['LCMSADMIN']){// ← 只认真实模块名okinfo("{$_L['url']['admin']}index.php?rootid={$loginrootid}&n=login&go=".urlencode($_L['url']['now']));}elseif($_L['LCMSADMIN']){

七、paycode(base64)/pay docheck SQL 注入

漏洞类型

SQL 注入(base64 编码参数绕过 WAF 和关键字过滤)

形成原因

这是被对手实打实利用过的点。前台pay入口的doindex()base64_decode($_L['form']['paycode'])json_decode,然后丢给PAYS::pay()。妙就妙在:base64 字符里不含任何 SQL 关键字,所以sqlinsert的关键字过滤和 WAF 全都被绕过了,解码后的order_no/payid再直接拼进 SQL。

对手就是拿这个点(配合 paycode 的cut/para这些 base64 参数)打的SET GLOBAL general_log写马——当然,后来确认他其实是直连 3306 干的,这个注入点更多是被当成了怀疑对象,但不管怎样它本身是实打实的洞。

原代码截图



源码

publicstaticfunctionorder_info($order_no){$order=sql_get(["order","order_no = '{$order_no}'"]);// ← 直接拼return$order;}publicstaticfunctionpayment_info($payid,$type=false){global$_L;$payment=LCMS::form(array("table"=>"payment","do"=>"get","id"=>$payid));// ← payid 没校验...}publicstaticfunctionorder($order=array()){...sql_update(["order",$order,"order_no = '{$order['order_no']}'"]);// ← 也拼...}publicstaticfunctionpay($paycode,$openid=""){$payment=self::payment_info($paycode['payid'],true);// ← payid 没 intval$payment?"":LCMS::X(404,"未找到支付参数");$order=$paycode['order_no']?self::order([...]):LCMS::X(404,"未找到订单信息");

修改后的代码

order_no白名单[A-Za-z0-9]+payid强制intvalfix_pays.py):

publicstaticfunctionorder_info($order_no){$order_no=preg_match('/^[A-Za-z0-9]+$/',$order_no)?$order_no:'';$order=sql_get(["order","order_no = '{$order_no}'"]);return$order;}publicstaticfunctionpayment_info($payid,$type=false){global$_L;$payid=intval($payid);$payment=LCMS::form(array("table"=>"payment","do"=>"get","id"=>$payid));...}publicstaticfunctionorder($order=array()){...$order['order_no']=preg_match('/^[A-Za-z0-9]+$/',$order['order_no'])?$order['order_no']:'';sql_update(["order",$order,"order_no = '{$order['order_no']}'"]);...}publicstaticfunctionpay($paycode,$openid=""){$paycode['payid']=intval($paycode['payid']);$paycode['order_no']=isset($paycode['order_no'])&&preg_match('/^[A-Za-z0-9]+$/',$paycode['order_no'])?$paycode['order_no']:'';$payment=self::payment_info($paycode['payid'],true);...}

八、支付回调 notify SQL 注入(XML 绕过 WAF)

漏洞类型

SQL 注入(php://input/$_POST直达,绕过 filterform 和 WAF)

形成原因

4 个支付回调的notify.php都是独立入口,不用登录,$postObj直接取自php://input(XML)或$_POST根本不走filterform过滤。这里最坑的是 wechat 的 XML:WAF 只查$_GET/$_POST/$_COOKIE,不查php://input,所以把注入 payload 塞进 XML 里就能绕过 WAF 直达 SQL。

当时用union select sleep(3),2,...,12 --做过时间盲注验证,lcms_order表 12 列,是能通的(报错注入因为 PDO SILENT 模式不回显,只能走时间盲注)。

原代码截图

源码

// wechat / wechat_agent —— WxPay.Notify.php(XML 注入,能绕过 WAF)$postObj=WxPayApi::FromXml(file_get_contents("php://input"));if($postObj['out_trade_no']){$order=sql_get(["order","order_no = '{$postObj['out_trade_no']}'"]);// ← 拼// alipay —— AliPay.Notify.php$postObj=$_POST;if($postObj['out_trade_no']){$order=sql_get(["order","order_no = '{$postObj['out_trade_no']}'"]);// ← 拼// codepay —— CodePay.Notify.php$postObj=$_POST;if($postObj['pay_id']&&$postObj['pay_no']){$order=sql_get(["order","order_no = '{$postObj['pay_id']}'"]);// ← 拼

修改后的代码

out_trade_no/pay_id全加白名单[A-Za-z0-9]+fix_notify.py):

// wechat —— WxPay.Notify.php$postObj=WxPayApi::FromXml(file_get_contents("php://input"));$postObj['out_trade_no']=isset($postObj['out_trade_no'])?preg_replace('/^[A-Za-z0-9]+$/','$0',$postObj['out_trade_no']):'';$postObj['out_trade_no']=preg_match('/^[A-Za-z0-9]+$/',$postObj['out_trade_no'])?$postObj['out_trade_no']:'';if($postObj['out_trade_no']){$order=sql_get(["order","order_no = '{$postObj['out_trade_no']}'"]);// wechat_agent —— WxPay.Notify.php$postObj=WxPayApi::FromXml(file_get_contents("php://input"));$postObj['out_trade_no']=preg_match('/^[A-Za-z0-9]+$/',$postObj['out_trade_no'])?$postObj['out_trade_no']:'';if($postObj['out_trade_no']){// alipay —— AliPay.Notify.php$postObj=$_POST;$postObj['out_trade_no']=preg_match('/^[A-Za-z0-9]+$/',$postObj['out_trade_no'])?$postObj['out_trade_no']:'';if($postObj['out_trade_no']){// codepay —— CodePay.Notify.php$postObj=$_POST;$postObj['pay_id']=preg_match('/^[A-Za-z0-9]+$/',$postObj['pay_id'])?$postObj['pay_id']:'';if($postObj['pay_id']&&$postObj['pay_no']){

九、WAF 盲区:不检查php://input

漏洞类型

防护缺失(WAF 覆盖不到请求体原始流)

形成原因

WAF v2 是我们自己部署在core/route.php里的,只检查$_GET / $_POST / $_COOKIE不读php://input。结果就是第八节那个 wechat XML 注入能从 WAF 眼皮底下溜过去——WAF 查不到,等于没查。

源码

<?phperror_reporting(E_ERROR|E_PARSE|E_CORE_ERROR|E_COMPILE_ERROR|E_USER_ERROR);date_default_timezone_set('Asia/Shanghai');/* ===== AWD WAF v2 START ===== */if(!defined('AWDBUGKU_WAF')){define('AWDBUGKU_WAF',1);functionawd_waf_block($t){header("HTTP/1.1 403 Forbidden");header("Status: 403 Forbidden");exit("Request blocked");}functionawd_waf_check($val){if(is_array($val)){foreach($valas$v){awd_waf_check($v);}return;}if(!is_string($val)||$val===''){return;}if(preg_match('/(\beval\s*\(|\bassert\s*\(|\bsystem\s*\(|\bpassthru\s*\(|\bshell_exec\s*\(|\bpopen\s*\(|\bproc_open\s*\(|`)/i',$val)){awd_waf_block('cmd');}if(preg_match('/(\bunion\b.+\bselect\b|\bsleep\s*\(|\bbenchmark\s*\(|\bextractvalue\s*\(|\bupdatexml\s*\(|\bload_file\s*\(|\boutfile\b|information_schema)/i',$val)){awd_waf_block('sqli');}if(preg_match('/((\bor\b|\band\b)\s*[\'\"]\s*[\'\"]?\s*\d+\s*=\s*\d+|(\bor\b|\band\b)\s*\d+\s*=\s*\d+|--\s|\/\*)/i',$val)){awd_waf_block('booli');}if(preg_match('/(\/etc\/passwd|\/flag\b|\.\.\/|\.\.\\\\)/i',$val)){awd_waf_block('path');}if(preg_match('/<\?(php|=)/i',$val)){awd_waf_block('shell');}}awd_waf_check($_GET);awd_waf_check($_POST);awd_waf_check($_COOKIE);// ← 漏了 php://input}/* ===== AWD WAF v2 END ===== */

修改后的代码

WAF v3 补上php://input前 8KB 的检查(fix_waf_v3.py):

awd_waf_check($_GET);awd_waf_check($_POST);awd_waf_check($_COOKIE);$awd_raw=@file_get_contents("php://input",false,null,0,8192);// ← 兜底读原始请求体if(is_string($awd_raw)&&$awd_raw!==''){awd_waf_check($awd_raw);}}/* ===== AWD WAF v2 END ===== */
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 17:53:06

Redis 八股文深度解析:线程模型、内存管理与事务机制全掌握

Redis 八股文这个话题&#xff0c;在面试圈里几乎跟“Java 集合”“MySQL 索引”一个级别&#xff0c;属于背了能过、不背就凉的高频区。不过我自己面过不少候选人&#xff0c;也当过被面的那一方&#xff0c;一个很深的感受是&#xff1a;把八股背熟的人很多&#xff0c;但能把…

作者头像 李华
网站建设 2026/9/9 14:54:39

R语言进阶——众数回归模型(modalreg)

目录0、引言1、核心思想1.1、目标函数的构成1.2、与均值和中位数的关系2、R语言包——modalreg2.1、包的简介2.2、快速上手安装安装与加载2.3、使用案例生成模拟数据&#xff08;内置工具&#xff09;训练模型查看结果与预测2.4、关键参数说明&#x1f4a1; 使用建议⚠️ 注意事…

作者头像 李华
网站建设 2026/9/11 7:31:10

Postgres备份恢复验证实战:用自动化脚本证明备份可恢复

备份这件事&#xff0c;很多团队其实一直处于“伪安全”状态&#xff1a;定时任务每天都在跑&#xff0c;备份文件一天比一天大&#xff0c;日志里写满了pg_dump: finished successfully&#xff0c;于是大家默认数据是安全的。但很少有人回答一个最关键的问题——当生产库真的…

作者头像 李华
网站建设 2026/9/10 15:10:43

皇室战争喷火狗球卡组攻略:熔岩猎犬与气球兵的防守反击与圣水调度

如果你在皇室战争的对局里见过这样的场面&#xff1a;熔岩猎犬慢悠悠飘向公主塔&#xff0c;气球兵在后面缓缓跟上&#xff0c;地狱飞龙从侧翼切入锁定敌方后排&#xff0c;地面防守单位只能干瞪眼——你可能会觉得&#xff0c;这个流派就是“攒费、下狗、下球、平推”。但真正…

作者头像 李华
网站建设 2026/9/10 18:47:51

STM32 DAC 实战:用 DMA 把定时器表变成波形,自制信号发生器

想用 STM32 出个正弦波、三角波、或者可调频的方波&#xff0c;最常用的笨办法是在主循环里一步步算好值、写进 DAC 数据寄存器。CPU 被这事儿占满不说&#xff0c;频率稍微高点波形就锯齿得没法看。 正确的玩法是让 DAC 自己按节奏出数&#xff1a;定时器当节拍器&#xff0c;…

作者头像 李华