added Spar PoC, added objection and frida guide

This commit is contained in:
wea_ondara
2023-09-01 20:04:03 +02:00
committed by wea_ondara
commit 7739693d63
17 changed files with 1966 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.3/userguide/building_java_projects.html in the Gradle documentation.
* This project uses @Incubating APIs which are subject to change.
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
application
}
repositories {
maven("https://jitpack.io")
mavenCentral()
}
dependencies {
implementation("com.github.SAP.gigya-java-sdk:sdk:3.3.2")
implementation("com.github.SAP.gigya-java-sdk:auth:3.3.2") // only if needed
implementation("org.json:json:20230227") //missing dep declaration in sdk
}
testing {
suites {
// Configure the built-in test suite
val test by getting(JvmTestSuite::class) {
// Use JUnit Jupiter test framework
useJUnitJupiter("5.9.3")
}
}
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
// encoding
languageVersion.set(JavaLanguageVersion.of(17))
}
}
application {
// Define the main class for the application.
mainClass.set("poc.App")
}

View File

@@ -0,0 +1,173 @@
package poc;
import com.gigya.auth.GSAnonymousRequest;
import com.gigya.socialize.GSKeyNotFoundException;
import com.gigya.socialize.GSObject;
import com.gigya.socialize.GSRequest;
import com.gigya.socialize.GSResponse;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class App {
private static final String authHost = "eu2.gigya.com";
private static final String authApiKey = "4_NfHE-cJJ9djefjHQU5x97Q";
private static final String apiProto = "https";
private static final String apiHost = "api-scp.spar-ics.com";
private static final String apiMount = "/mobile/b2c/apps/spar/at/be/v1/";
public static void main(String[] args) {
var loginProcess = new LoginProcess("", "");
loginProcess.perform().join();
}
public static class LoginProcess {
private final String username;
private final String password;
private String sessionToken;
private String sessionSecret;
private String uid;
private String jwt;
private Map<String, JSONObject> receiptsByBonId = new HashMap<>();
private final Map<String, byte[]> receiptsPdfByBonId = new HashMap<>();
public LoginProcess(String username, String password) {
this.username = username;
this.password = password;
}
public CompletableFuture<LoginProcess> perform() {
return CompletableFuture.supplyAsync(() -> {
login();
getJWT();
return null;
})
.thenComposeAsync(v -> receipts())
.thenComposeAsync(v -> {
var future = CompletableFuture.<Void>completedFuture(null);
for (String receiptBonId : receiptsByBonId.keySet()) {
future = future.thenCompose(v2 -> receiptById(receiptBonId));
}
return future;
})
.thenAccept(v -> dump())
.thenApply(v -> this);
}
private void login() {
var loginRequest = new GSAnonymousRequest(authApiKey, authHost, "accounts.login");
loginRequest.setParam("loginID", username);
loginRequest.setParam("password", password);
loginRequest.setParam("loginMode", "standard");
loginRequest.setParam("targetEnv", "mobile");
final GSResponse response = loginRequest.send();
if (response.getErrorCode() != 0) {
throw new RuntimeException();
}
try {
sessionToken = response.getData().getObject("sessionInfo").getString("sessionToken");
sessionSecret = response.getData().getObject("sessionInfo").getString("sessionSecret");
uid = response.getData().getString("UID");
} catch (GSKeyNotFoundException e) {
throw new RuntimeException(e);
}
}
private void getJWT() {
var jwtRequest = new GSRequest(authApiKey, sessionSecret, null, "accounts.getJWT", new GSObject(), true);
// var jwtRequest = new GSAuthRequest(authApiKey, sessionSecret, sessionToken, "accounts.getJWT", new GSObject(), true);
jwtRequest.setAPIDomain(authHost);
jwtRequest.setParam("UID", uid);
jwtRequest.setParam("oauth_token", sessionToken);
jwtRequest.setParam("targetEnv", "mobile");
jwtRequest.setParam("fields", "UID,isVerified");
final GSResponse response = jwtRequest.send();
if (response.getErrorCode() != 0) {
throw new RuntimeException();
}
try {
this.jwt = response.getData().getString("id_token");
} catch (GSKeyNotFoundException e) {
throw new RuntimeException(e);
}
}
private CompletableFuture<Void> receipts() {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiProto + "://" + apiHost + apiMount + "v1/receipts"))
.header("Authorization", "Bearer " + this.jwt)
.build();
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(res -> {
if (res.statusCode() != 200) {
throw new RuntimeException("Status code: " + res.statusCode() + "\n" + res.body());
}
return res;
})
.thenApply(HttpResponse::body)
.thenAccept(body -> {
var receipts = new JSONObject(body).getJSONArray("receipt");
this.receiptsByBonId = IntStream.range(0, receipts.length())
.mapToObj(receipts::getJSONObject)
.collect(Collectors.toMap(e -> e.getString("bonId"), e -> e));
});
}
private CompletableFuture<Void> receiptById(String bonId) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiProto + "://" + apiHost + apiMount + "v1/receipt/" + bonId))
.header("Authorization", "Bearer " + this.jwt)
.build();
return client.sendAsync(request, HttpResponse.BodyHandlers.ofByteArray())
.thenApply(res -> {
if (res.statusCode() != 200) {
throw new RuntimeException("Status code: " + res.statusCode() + "\n" + new String(res.body()));
}
return res;
})
.thenApply(HttpResponse::body)
.thenAccept(body -> this.receiptsPdfByBonId.put(bonId, body));
}
private void dump() {
try {
new File("dump").mkdirs();
//dump meta
var j = new JSONArray();
this.receiptsByBonId.values().forEach(j::put);
Files.writeString(Path.of("dump", "receipts.json"), j.toString(2),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
//dump pdfs
for (var e : this.receiptsPdfByBonId.entrySet()) {
Files.write(Path.of("dump", e.getKey() + ".pdf"), e.getValue(),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -0,0 +1,14 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package poc;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class AppTest {
@Test void appHasAGreeting() {
// App classUnderTest = new App();
// assertNotNull(classUnderTest.getGreeting(), "app should have a greeting");
}
}