2018 CSAW

欢迎关注我的新博客地址:http://mmmmmmlei.cn

之前9月份事情很多没有打CSAW ,听说题质量不错就去做了做,不会的就去复现了一波,跟着师傅们的wp学到了不少东西。

Web

Ldab

这道题开始做的时候试了一波注入姿势,没有什么卵用,后来才知道考察的是 LDAP 的注入。

关于 LDAP 及注入的知识点,可以参考这几篇博客:

  1. https://www.jianshu.com/p/d94673be9ed0

  2. http://blog.51cto.com/407711169/1439623

  3. LDAP 注入常用payload

看这道题,flag 应该就藏在某一项中,试一下查出所有项:

*)(uid=*

没有 flag,应该是做了什么过滤,猜测后台查询语句可能是这样的:

(&(name=输入)(name!=flag))

在&的条件下,我们的 payload 带入,变为

(&(name=*)(uid=*)(name!=flag))

flag 依然无法查询到。

所以思路是闭合掉前面的 &,再构造一个查询语句,payload:

*)(uid=*))(|(uid=*

代入查询语句变为:

(&(name=*)(uid=*))(|(uid=*)(name!=flag))

这样过滤flag前面限制变成了 " | ",查询到flag:

flag{ld4p_inj3ction_i5_a_th1ng}

sso

题目描述:

Don't you love undocumented APIs
Be the admin you were always meant to be
http://web.chal.csaw.io:9000
Update chal description at: 4:38 to include solve details
Aesthetic update for chal at Sun 7:25 AM

查看源码:

<h1>Welcome to our SINGLE SIGN ON PAGE WITH FULL OAUTH2.0!</h1>
<a href="/protected">.</a>
<!--
Wish we had an automatic GET route for /authorize... well they'll just have to POST from their own clients I guess
POST /oauth2/token
POST /oauth2/authorize form-data TODO: make a form for this route
--!>

应该是基于 OAuth2.0 协议的身份验证,去补一波知识…

关于OAuth2.0的知识,可以参考以下几篇博客:

  1. 阮一峰的博客

  2. OAuth 2.0攻击方法

这道题涉及的验证模式是授权码模式。流程如下:

  1. 用户访问客户端,后者将前者导向认证服务器。
  2. 用户选择是否给予客户端授权。
  3. 假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向 URI "(redirection URI),同时附上一个授权码。
  4. 客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

分析此题,我们要拿到 token 去访问 http://web.chal.csaw.io:9000/protected 得到flag,过程基本如下:

先去访问 /oauth2/authorize,构造 Post 请求拿到 code,带着这个code去访问 /oauth2/token,得到token去访问 /oauth2/protected 去找flag。

首先访问 /oauth2/authorize,注意要在 Post 请求中加 “response_type=code”。redirect_uri 是重定向的url,与后面填的一致就可以。
image.png

拿着这个 code 去访问 /oauth2/token,注意 Post 参数的格式:
image.png
payload:

grant_type=authorization_code&code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vd2ViLmNoYWwuY3Nhdy5pbzo5MDAwL3Byb3RlY3RlZCIsImlhdCI6MTUzODk3OTY4OCwiZXhwIjoxNTM4OTgwMjg4fQ.EmiNRIdeLAij3UUnBP2763GTsBtu-BFMi14yAoQRWFk&redirect_uri=http://web.chal.csaw.io:9000/protected

得到 token,进行 jwt 在线解码:
image.png
这里的 ufoundme! 就是加密的密钥,根据题目提示把 user 改为 admin ,下面密钥换成 ufoundme!
image.png
拿着这个新的 token 去访问 http://web.chal.csaw.io:9000/protected 得到flag:
image.png

flag: flag{JsonWebTokensaretheeasieststorage-lessdataoptiononthemarket!theyrelyonsupersecureblockchainlevelencryptionfortheirmethods}

参考:

  1. https://www.secpulse.com/archives/75785.html

  2. https://delcoding.github.io/2018/09/csaw-writeup2/

Crypto

babycrypto

题目描述:

yeeeeeeeeeeeeeeeeeeeeeeeeeeeeeet
single yeet yeeted with single yeet == 0
yeeet
what is yeet?
yeet is yeet
Yeetdate: yeeted yeet at yeet: 9:42 pm

密文给了一串base64:

s5qQkd+WjN+e34+NkJiNnpKSmo3fiJeQ356Mj5aNmozfi5DfnI2anoua34+NkJiNnpKM34uXnovfl5qTj9+PmpCPk5rfm5Dfk5qMjNHft5rfiJ6Ri4zfi5Dfj4qL356Ki5CSnouWkJHfmZaNjIvT356Rm9+MnJ6Tnp2Wk5aLht+ek5CRmIyWm5rR37ea35uNmp6SjN+Qmd+e34iQjZOb34iXmo2a34uXmt+akZuTmoyM356Rm9+Ll5rflpGZlpGWi5rfnZqckJKa342anpOWi5aajN+LkN+SnpGUlpGb09+ekZvfiJeajZrfi5ea34uNiprfiZ6TiprfkJnfk5aZmt+WjN+PjZqMmo2JmpvRmZOemISblpmZlprSl5qTk5KekdKYz4+XzI2FjZ6wps61npPLnLeeuabGrKithr6uyZ63gg==

密文解码是乱码

说了这么多,yeet 到底是什么,通过第二句猜测可能是异或(自己和自己 yeet 为0)

逐字节异或 只有 256 种情况,写出爆破脚本:

import base64
ciphertext="s5qQkd+WjN+e34+NkJiNnpKSmo3fiJeQ356Mj5aNmozfi5DfnI2anoua34+NkJiNnpKM34uXnovfl5qTj9+PmpCPk5rfm5Dfk5qMjNHft5rfiJ6Ri4zfi5Dfj4qL356Ki5CSnouWkJHfmZaNjIvT356Rm9+MnJ6Tnp2Wk5aLht+ek5CRmIyWm5rR37ea35uNmp6SjN+Qmd+e34iQjZOb34iXmo2a34uXmt+akZuTmoyM356Rm9+Ll5rflpGZlpGWi5rfnZqckJKa342anpOWi5aajN+LkN+SnpGUlpGb09+ekZvfiJeajZrfi5ea34uNiprfiZ6TiprfkJnfk5aZmt+WjN+PjZqMmo2JmpvRmZOemISblpmZlprSl5qTk5KekdKYz4+XzI2FjZ6wps61npPLnLeeuabGrKithr6uyZ63gg=="
cipher=base64.b64decode(ciphertext)
for i in range(0,256):
    result=""
    for s in cipher:
        result+=chr(ord(s)^i)
    if "flag" in result:
        print result

flag: flag{diffie-hellman-g0ph3rzraOY1Jal4cHaFY9SWRyAQ6aH}

lowe

I personally prefer Home Depot
XOR Passes are the easiest way to use numbers to encrypt!
By Kris Kwiatkowski, Cloudflare

附件有三个:

  • file.enc
  • key.enc
  • pubkey.pem

file.enc 是一串 base64 编码,解码是一串乱码,看起来像是加密过。

kStoynmN5LSniue0nDxli9csSrBgexZ/YOo5e+MUkfJKwvht8hHsYyMGVYzMlOp9sAFBrPCbm4UA4n7oMr2zlg==

key.enc是 1533bit 的一个数。

219135993109607778001201845084150602227376141082195657844762662508084481089986056048532133767792600470123444605795683268047281347474499409679660783370627652563144258284648474807381611694138314352087429271128942786445607462311052442015618558352506502586843660097471748372196048269942588597722623967402749279662913442303983480435926749879440167236197705613657631022920490906911790425443191781646744542562221829319509319404420795146532861393334310385517838840775182

pubkey.pem 是RSA公钥文件。

-----BEGIN PUBLIC KEY-----
MIHdMA0GCSqGSIb3DQEBAQUAA4HLADCBxwKBwQDPcH7tl5AXt/b0dv87plVZrbGC
4Hz6IzOx7AVrf3uWEkBU8fV0iwTDaU6Q8Nmf7gWEqHpwgXWA1JOTMhuyCAf/3iWk
yKvUbZXB43QNnmQf53+bls7K6RjmeiSJUrXaga53Qr2uUbEpJFlzQVBXrnXft1p4
6CQ3nlJQZZLDdQ6aHH5wG+6N38epynJTTNOwlXn4ek6zdvkmfNGhbh5XkJXFuG9L
jyT7YT8Ip+DkddJVVq5ByM7iSOkNrJZdxH3btMUCAQM=
-----END PUBLIC KEY-----

首先在线提取出 RSA 公钥的n和e (选择 openssl 提取也可以)。发现 n 是1536bit,而 e 仅仅为 3。
image.png
分析以上条件,不难得出 key.enc 是 RSA 加密的 c,位数相近。 此题 e 这么小,猜想可能直接开三次方开出来,或者 **c + i* n **能够直接开三次方,其中 i 穷举。

试了一下发现成功,得到 RSA 明文 m,根据题目提示和 file.enc 进行异或,得到 flag,解题脚本如下:

import gmpy2
import base64
import libnum
n=1953100985460341348696462250270875098931515807146586756296095446519328460202594322688077959911801412881736536007030245814199784734114468379391959242638228445246656155129859794350223734103552981321896683545886584718379382489138858499065228901412805708175575610007278296746952620830529848517741610397035368508736304074009571123132231492002047409382240786830369954266084929667038697671614351425836882238175963587766360974168461069129309445949172255481878016805287109
e=3
key=219135993109607778001201845084150602227376141082195657844762662508084481089986056048532133767792600470123444605795683268047281347474499409679660783370627652563144258284648474807381611694138314352087429271128942786445607462311052442015618558352506502586843660097471748372196048269942588597722623967402749279662913442303983480435926749879440167236197705613657631022920490906911790425443191781646744542562221829319509319404420795146532861393334310385517838840775182
data=base64.b64decode(open("file.enc","rb").read())
data=int(data.encode("hex"),16)
for i in range(10000):
    if gmpy2.iroot(key+i*n,e)[1]:
        m=gmpy2.iroot(key+i*n,e)[0]
plain=libnum.n2s(m^data)
print plain

flag: flag{saltstacksaltcomit5dd304276ba5745ec21fc1e6686a0b28da29e6fc}

Misc

bin_t

题目描述:

Binary trees let you do some interesting things. Can you balance a tree?
nc misc.chal.csaw.io 9001
Equal nodes should be inserted to the right of the parent node. You should balance the tree as you add nodes.

ACM入门级,AVL树的生成和树的前序遍历,贴上python代码:

#coding:utf-8
class TreeNode(object):
    def __init__(self):
        self.data=0
        self.left=None
        self.right=None
        self.height=0
class BTree(object):
    def __init__(self):
        self.root=None
        self.result=""
    def __Max(self,h1,h2):
        if h1>h2:
            return h1
        elif h1<=h2:
            return h2
    def __LL(self,r):#左左情况,向右旋转
        node=r.left
        r.left=node.right
        node.right=r
        r.height=self.__Max(self.getHeight(r.right),self.getHeight(r.left))+1
        node.height=self.__Max(self.getHeight(node.right),self.getHeight(node.left))+1
        return node
    def __RR(self,r):#右右,左旋
        node = r.right
        r.right = node.left
        node.left = r
        r.height = self.__Max(self.getHeight(r.right), self.getHeight(r.left)) + 1
        node.height = self.__Max(self.getHeight(node.right), self.getHeight(node.left)) + 1
        return node
    def __LR(self,r):#左右,先左旋再右旋
        r.left=self.__RR(r.left)
        return self.__LL(r)
    def __RL(self,r):#右左,先右旋再左旋
        r.right=self.__LL(r.right)
        return self.__RR(r)
    def __insert(self,data,r):
        if r==None:
            node=TreeNode()
            node.data=data
            return node
        elif data==r.data:
            return r
        elif data<r.data:
            r.left=self.__insert(data,r.left)
            if self.getHeight(r.left)-self.getHeight(r.right)>=2:
                if data<r.left.data:
                    r=self.__LL(r)
                else:
                    r=self.__LR(r)
        else:
            r.right=self.__insert(data,r.right)
            if self.getHeight(r.right)-self.getHeight(r.left)>=2:
                if data>r.right.data:
                    r=self.__RR(r)
                else:
                    r=self.__RL(r)
        r.height=self.__Max(self.getHeight(r.left),self.getHeight(r.right))+1
        return r
    # 删除data节点
    def __delete(self,data,r):
        if r==None:
            print "don't have %d"%data
            return r
        elif r.data==data:
            if r.left==None:#如果只有右子树,直接将右子树赋值到此节点
                return r.right
            elif r.right==None:#如果只有左子树,直接将左子树赋值到此节点
                return r.left
            else:#如果同时有左右子树
                if self.getHeight(r.left)>self.getHeight(r.right):#左子树高度大于右子树
                    #找到最右节点 返回节点值 并删除该节点
                    node=r.left
                    while(node.right!=None):
                        node=node.right
                    r=self.__delete(node.data,r)
                    r.data=node.data
                    return r
                else:#右子树高度大于左子树
                    node=r.right
                    while node.left!=None:
                        node=node.left
                    r=self.__delete(node.data,r)
                    r.data=node.data
                    return r
        elif data<r.data:
            r.left=self.__delete(data,r.left)#在左子树中删除
            if self.getHeight(r.right)-self.getHeight(r.left)>=2:#右子树高度与左子树高度相差超过1
                if self.getHeight(r.right.left)>self.getHeight(r.right.right):
                    r=self.__RL(r)
                else:
                    r=self.__RR(r)
        elif data>r.data:
            r.right=self.__delete(data,r.right)#右子树中删除
            if self.getHeight(r.left)-self.getHeight(r.right)>=2:#左子树与右子树高度相差超过1
                if self.getHeight(r.left.right)>self.getHeight(r.left.left):
                    r=self.__LR(r)
                else:
                    r=self.__LL(r)
        r.height=self.__Max(self.getHeight(r.left),self.getHeight(r.right))+1
        return r
    #先序遍历
    def __show(self,root):
        if root!=None:
            self.result+= str(root.data)+","
            self.__show(root.left)
            self.__show(root.right)
        else:
            return 0
    def Insert(self,data):
        self.root=self.__insert(data,self.root)
        return self.root
    def Delete(self,data):
        self.root=self.__delete(data,self.root)
    #求结点的高度
    def getHeight(self,node):
        if node==None:
            return -1
        #print node
        return node.height
    def Show(self):
        self.__show(self.root)
if __name__=='__main__':
    bi=BTree()
    array=[40,84,21,16,50,28,32,10,46,55,22,4,50,76,45,56,42,6,89,99,21,16,72,47,96,29,46,97,10,58,63,83,40,65,24,65,72,100,11,52,57,77,49,61,5,85,73,49,98,90,81,39,12,73,80,19,69,78,27,25,84,92,79,98,21,8,48,2,34,49,35,21,24,86,10,60,39,28,84,80,61,6,73,67,38,78,70,12,3,94,46,10,91,12,14,69,1,81,56,21]
    for i in array:
        bi.Insert(i)
    bi.Show()
    print bi.result

flag: flag{HOW_WAS_IT_NAVIGATING_THAT_FOREST?}

Short Circuit

Start from the monkey’s paw and work your way down the high voltage line, for every wire that is branches off has an element that is either on or off. Ignore the first bit. Standard flag format.

图片:
20180915_074129.jpg
题都没看懂… 太真实了

网上搜到师傅的 wp,就是一张图片,绝了:
short-circuit.jpg
打扰了。

flag:flag{owmyhand}

Algebra

计算一元一次方程,开始想一个一个手算,实在算不动,太多了。写个python脚本:

因为我的那个计算算法可能会出错…所以加了捕获异常,捕获到异常直接重新连接…

# -*- coding:utf-8 -*-
import socket
def solve(eq, var="X"):
    eq1 = eq.replace("=", "-(") + ")"
    c = eval(eq1, {var: 1j})
    if (-c.real == 0):
        return 0
    else:
        return -c.real / c.imag
while 1:
    try:
        time = 1
        sc = socket.socket()
        host = "misc.chal.csaw.io"
        port = 9002
        addr = (host, port)
        sc.connect(addr)
        print sc.recv(1024)
        while 1:
            print "-----------round {}--------------".format(time)
            data = sc.recv(1024)
            print data
            if "flag" in data:
                exit()
            if time == 1:
                shizi = data.split('\n')[0]
            else:
                shizi = data.split('\n')[1]
            result = str(solve(shizi))
            print "result:", result
            sc.send(result + "\n")
            time += 1
    except BaseException:
        if "flag" in data:
            break
        sc.shutdown(2)
        sc.close()
        continue

flag: flag{y0u_s0_60od_aT_tH3_qU1cK_M4tH5}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值