[+] Include Kotlin source code
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.idea/
|
.idea/
|
||||||
*.iml
|
*.iml
|
||||||
|
.gradle/
|
||||||
|
|||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '1.3.72'
|
||||||
|
id 'org.jetbrains.kotlin.plugin.serialization' version '1.3.70'
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'org.hydev.experiment'
|
||||||
|
version '0.0.0.1'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/org.apache.commons/httpclient
|
||||||
|
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.9'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/com.googlecode.aviator/aviator
|
||||||
|
compile group: 'com.googlecode.aviator', name: 'aviator', version: '5.1.4'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/com.google.zxing/core
|
||||||
|
compile group: 'com.google.zxing', name: 'core', version: '3.4.1'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/com.google.zxing/javase
|
||||||
|
compile group: 'com.google.zxing', name: 'javase', version: '3.4.1'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/com.beust/jcommander
|
||||||
|
compile group: 'com.beust', name: 'jcommander', version: '1.78'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/commons-io/commons-io
|
||||||
|
compile group: 'commons-io', name: 'commons-io', version: '2.8.0'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/com.google.guava/guava
|
||||||
|
compile group: 'com.google.guava', name: 'guava', version: '30.0-jre'
|
||||||
|
|
||||||
|
// https://mvnrepository.com/artifact/org.hydev/HyLogger
|
||||||
|
compile group: 'org.hydev', name: 'HyLogger', version: '2.1.0.378'
|
||||||
|
|
||||||
|
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||||
|
}
|
||||||
|
|
||||||
|
compileKotlin {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
|
||||||
|
compileTestKotlin {
|
||||||
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes "Main-Class": "org.hydev.experiment.MainKt"
|
||||||
|
}
|
||||||
|
|
||||||
|
from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
kotlin.code.style=official
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
rootProject.name = 'Hackergame2020'
|
||||||
|
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
package org.hydev.experiment
|
||||||
|
|
||||||
|
import org.hydev.logger.HyLogger
|
||||||
|
import org.hydev.logger.HyLoggerConfig
|
||||||
|
import org.hydev.logger.appenders.FileAppender
|
||||||
|
import javax.script.ScriptEngine
|
||||||
|
import javax.script.ScriptEngineManager
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
val symbols = "+-*/%^&| ".toCharArray()
|
||||||
|
|
||||||
|
val scriptEngineManager = ScriptEngineManager()
|
||||||
|
val engine: ScriptEngine = scriptEngineManager.getEngineByName("AviatorScript")
|
||||||
|
|
||||||
|
// Combination presets for the prime method
|
||||||
|
fun getCombs(vararg strs: String) = strs.map { str -> str.split(" ").map { it.toInt() } }
|
||||||
|
val comb1 = getCombs("114514")
|
||||||
|
val comb2 = getCombs("1 14514", "11 4514", "114 514", "1145 14", "11451 4")
|
||||||
|
val comb3 = getCombs("1 1 4514", "1 14 514", "1 145 14", "1 1451 4", "11 4 514", "11 45 14", "11 451 4", "114 5 14", "114 51 4", "1145 1 4")
|
||||||
|
val comb4 = getCombs("1 1 4 514", "1 1 45 14", "1 1 451 4", "1 14 5 14", "1 14 51 4", "11 4 5 14", "11 4 51 4", "11 45 1 4", "114 5 1 4")
|
||||||
|
val comb5 = getCombs("1 1 4 5 14", "1 1 4 51 4", "1 1 45 1 4", "1 14 5 1 4", "11 4 5 1 4")
|
||||||
|
val comb6 = getCombs("1 1 4 5 1 4")
|
||||||
|
val combs = listOf(getCombs(), comb1, comb2, comb3, comb4, comb5, comb6)
|
||||||
|
|
||||||
|
val clipboard = ClipboardTools()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write a description for this class!
|
||||||
|
*
|
||||||
|
* @author HyDEV Team (https://github.com/HyDevelop)
|
||||||
|
* @author Hykilpikonna (https://github.com/hykilpikonna)
|
||||||
|
* @author Vanilla (https://github.com/VergeDX)
|
||||||
|
* @since 2020-11-03 21:44
|
||||||
|
*/
|
||||||
|
fun main(args: Array<String>)
|
||||||
|
{
|
||||||
|
// HyLogger
|
||||||
|
HyLoggerConfig.appenders.add(FileAppender("./logs", "ctf-mini-miner.log"))
|
||||||
|
//HyLoggerConfig.installSysOut()
|
||||||
|
|
||||||
|
// Actual program starts
|
||||||
|
val lastClip = clipboard.clipboardContents
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
print("\n")
|
||||||
|
println("Waiting for clipboard...")
|
||||||
|
|
||||||
|
// Wait for clipboard
|
||||||
|
while (clipboard.clipboardContents == lastClip || clipboard.getInt() == null) { Thread.sleep(200) }
|
||||||
|
println("Clipboard received!")
|
||||||
|
val target = clipboard.getInt()!!
|
||||||
|
findEquation(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findEquation(target: Int)
|
||||||
|
{
|
||||||
|
for (offsetIndex in 2..220)
|
||||||
|
{
|
||||||
|
val primeTotalOffset = if (offsetIndex % 2 == 0) offsetIndex / 2 else -offsetIndex / 2
|
||||||
|
|
||||||
|
var expr = findEquationHelper(target - primeTotalOffset)
|
||||||
|
|
||||||
|
// Apply total offset
|
||||||
|
expr = if (primeTotalOffset >= 0) "${"-~".repeat(primeTotalOffset)}($expr)"
|
||||||
|
else "${"~-".repeat(-primeTotalOffset)}($expr)"
|
||||||
|
|
||||||
|
// Check expression length
|
||||||
|
if (expr.length < 255)
|
||||||
|
{
|
||||||
|
println("Found! $expr")
|
||||||
|
|
||||||
|
clipboard.clipboardContents = expr
|
||||||
|
|
||||||
|
// Check correct
|
||||||
|
if (engine.eval(expr).toString().toInt() == target) println("Checked, correct!")
|
||||||
|
else error("Equation does not match :(")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else continue
|
||||||
|
}
|
||||||
|
|
||||||
|
error("Failed to find expression :(")
|
||||||
|
|
||||||
|
//
|
||||||
|
// // If a short enough expression is not found, use the prime number method
|
||||||
|
// var originalPrimes = target.getPrimeFactors()
|
||||||
|
// var primeTotalOffset = 0
|
||||||
|
//
|
||||||
|
// // Reduce prime targets to the least "prime" number around it (Eg. 3347 -> 3346)
|
||||||
|
// for (offset in -searchRange..searchRange)
|
||||||
|
// {
|
||||||
|
// if (target + offset < 0) continue
|
||||||
|
//
|
||||||
|
// val primes = (target - offset).getPrimeFactors()
|
||||||
|
//
|
||||||
|
// // New least "prime" number found!
|
||||||
|
// if (primes.size > originalPrimes.size)
|
||||||
|
// {
|
||||||
|
// originalPrimes = primes
|
||||||
|
// primeTotalOffset = offset
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findEquationHelper(target: Int): String
|
||||||
|
{
|
||||||
|
val originalPrimes = target.getPrimeFactors()
|
||||||
|
|
||||||
|
var closestPrimeComb = listOf<Int>()
|
||||||
|
var closestPrimePerm = listOf<Int>()
|
||||||
|
var closestPrimeOffset = Int.MAX_VALUE
|
||||||
|
|
||||||
|
// Loop through all possible separations for combinations
|
||||||
|
for (n in 1..6)
|
||||||
|
{
|
||||||
|
// Loop through all combinations
|
||||||
|
for (combination in combs[n])
|
||||||
|
{
|
||||||
|
// Loop through all permutations of prime numbers
|
||||||
|
for (primePerm in organizePrimes(originalPrimes, n).permute())
|
||||||
|
{
|
||||||
|
if (primePerm.size != n || combination.size != n)
|
||||||
|
{
|
||||||
|
print("EERRRORRR")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the total offset
|
||||||
|
var offset = 0
|
||||||
|
for (i in 0 until n)
|
||||||
|
{
|
||||||
|
offset += abs(primePerm[i] - combination[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// New closest found
|
||||||
|
if (offset < closestPrimeOffset)
|
||||||
|
{
|
||||||
|
closestPrimeComb = combination
|
||||||
|
closestPrimePerm = primePerm
|
||||||
|
closestPrimeOffset = offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found, construct expression
|
||||||
|
var expr = ""
|
||||||
|
for (i in closestPrimeComb.indices)
|
||||||
|
{
|
||||||
|
val value = closestPrimePerm[i]
|
||||||
|
val actual = closestPrimeComb[i]
|
||||||
|
|
||||||
|
expr += when
|
||||||
|
{
|
||||||
|
actual == value -> actual
|
||||||
|
actual < value -> "${"~-".repeat(value - actual - 1)}~$actual"
|
||||||
|
else -> "${"~-".repeat(actual - value)}$actual"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add multiplication symbol
|
||||||
|
if (i != closestPrimeComb.size - 1) expr += "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail
|
||||||
|
if (expr.length > 255) return expr
|
||||||
|
|
||||||
|
// Evaluate expression and add neg sign if necessary
|
||||||
|
val eval = engine.eval(expr).toString().toInt()
|
||||||
|
if (eval < 0) expr = "-$expr"
|
||||||
|
return expr
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findEquationFallback(target: Int)
|
||||||
|
{
|
||||||
|
// The symbol brute force method
|
||||||
|
var closest = ""
|
||||||
|
var closestValue = Int.MIN_VALUE
|
||||||
|
var closestOffset = Int.MAX_VALUE
|
||||||
|
|
||||||
|
outer@for (one in symbols)
|
||||||
|
{
|
||||||
|
for (two in symbols)
|
||||||
|
{
|
||||||
|
for (three in symbols)
|
||||||
|
{
|
||||||
|
for (four in symbols)
|
||||||
|
{
|
||||||
|
for (five in symbols)
|
||||||
|
{
|
||||||
|
val text = "1${one}1${two}4${three}5${four}1${five}4".replace(" ", "")
|
||||||
|
val evalString = engine.eval(text).toString()
|
||||||
|
if (evalString.contains("E")) continue
|
||||||
|
val eval = evalString.toDouble().roundToInt()
|
||||||
|
|
||||||
|
// New closest found
|
||||||
|
val offset = abs(eval - target)
|
||||||
|
if (offset < closestOffset)
|
||||||
|
{
|
||||||
|
closest = text
|
||||||
|
closestValue = eval
|
||||||
|
closestOffset = offset
|
||||||
|
|
||||||
|
if (closestOffset < 50) break@outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HyLogger.general.timing.time().reset()
|
||||||
|
|
||||||
|
// Create expression
|
||||||
|
val expr = if (closestValue <= target) "${"-~".repeat(target - closestValue)}($closest)"
|
||||||
|
else "-(${"-~".repeat(closestValue - target)}-($closest))"
|
||||||
|
|
||||||
|
// Check expression length
|
||||||
|
if (expr.length < 255) println("Found! $expr")
|
||||||
|
else findEquation(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organize a list of primes so that it contains ${count} numbers
|
||||||
|
*
|
||||||
|
* @param primes
|
||||||
|
* @param count
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun organizePrimes(primes: List<Int>, count: Int): MutableList<Int>
|
||||||
|
{
|
||||||
|
val new = ArrayList<Int>(primes)
|
||||||
|
|
||||||
|
// Eg. [2, 2, 2].size < 6 -> [1, 1, 1, 2, 2, 2]
|
||||||
|
if (primes.size < count)
|
||||||
|
{
|
||||||
|
for (i in 1..count - primes.size) new.add(0, 1)
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eg. [2, 2, 2, 3, 3, 3, 5, 5, 5].size > 6 -> [2, 3, 3, 3, 4, 5, 5, 5] -> [3, 3, 4, 5, 5, 5, 6] -> [4, 5, 5, 5, 6, 9]
|
||||||
|
while (new.size > count) new.apply { add(removeAt(0) * removeAt(0)); sort() }
|
||||||
|
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Int.getPrimeFactors(): List<Int>
|
||||||
|
{
|
||||||
|
// It is a prime
|
||||||
|
if (this <= 2) return listOf(this)
|
||||||
|
|
||||||
|
// Find prime numbers
|
||||||
|
var temp = this
|
||||||
|
val primes = ArrayList<Int>()
|
||||||
|
for (i in 2 until temp)
|
||||||
|
{
|
||||||
|
while (temp % i == 0)
|
||||||
|
{
|
||||||
|
primes.add(i)
|
||||||
|
temp /= i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(temp > 2) primes.add(temp)
|
||||||
|
|
||||||
|
return primes
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> List<T>.permute() = permuteHelper().distinct()
|
||||||
|
|
||||||
|
// https://code.sololearn.com/c24EP02YuQx3/#kt
|
||||||
|
private fun <T> List<T>.permuteHelper(): List<List<T>>
|
||||||
|
{
|
||||||
|
if (size == 1) return listOf(this)
|
||||||
|
|
||||||
|
val perms = mutableListOf<List<T>>()
|
||||||
|
val sub = this[0]
|
||||||
|
|
||||||
|
for(perm in drop(1).permuteHelper())
|
||||||
|
{
|
||||||
|
for (i in 0..perm.size)
|
||||||
|
{
|
||||||
|
val newPerm = perm.toMutableList()
|
||||||
|
newPerm.add(i, sub)
|
||||||
|
perms.add(newPerm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return perms
|
||||||
|
}
|
||||||
+218
@@ -0,0 +1,218 @@
|
|||||||
|
package org.hydev.experiment
|
||||||
|
|
||||||
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.UnstableDefault
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonConfiguration
|
||||||
|
import org.apache.http.client.methods.HttpGet
|
||||||
|
import org.apache.http.client.methods.HttpPost
|
||||||
|
import org.apache.http.client.protocol.HttpClientContext
|
||||||
|
import org.apache.http.entity.StringEntity
|
||||||
|
import org.apache.http.impl.client.BasicCookieStore
|
||||||
|
import org.apache.http.impl.client.HttpClients
|
||||||
|
import org.apache.http.impl.cookie.BasicClientCookie
|
||||||
|
import org.apache.http.util.EntityUtils
|
||||||
|
import org.hydev.logger.HyLoggerConfig
|
||||||
|
import org.hydev.logger.appenders.FileAppender
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write a description for this class!
|
||||||
|
*
|
||||||
|
* @author HyDEV Team (https://github.com/HyDevelop)
|
||||||
|
* @author Hykilpikonna (https://github.com/hykilpikonna)
|
||||||
|
* @author Vanilla (https://github.com/VergeDX)
|
||||||
|
* @since 2020-11-02 15:51
|
||||||
|
*/
|
||||||
|
@OptIn(UnstableDefault::class)
|
||||||
|
@ImplicitReflectionSerializer
|
||||||
|
fun main(args: Array<String>)
|
||||||
|
{
|
||||||
|
// Json
|
||||||
|
val json = Json(JsonConfiguration(isLenient = true))
|
||||||
|
|
||||||
|
// HyLogger
|
||||||
|
HyLoggerConfig.appenders.add(FileAppender("./logs", "ctf-doggy.log"))
|
||||||
|
HyLoggerConfig.installSysOut()
|
||||||
|
|
||||||
|
// Create http client
|
||||||
|
val builder = HttpClients.custom()
|
||||||
|
val context = HttpClientContext.create()
|
||||||
|
val cookies = BasicCookieStore()
|
||||||
|
context.cookieStore = cookies
|
||||||
|
builder.setDefaultCookieStore(cookies)
|
||||||
|
val client = builder.build()
|
||||||
|
|
||||||
|
// CTF session
|
||||||
|
val sessionFile = File("doggy-session.txt")
|
||||||
|
cookies.addCookie(BasicClientCookie("session", sessionFile.readText().replace("\n", ""))
|
||||||
|
.apply { domain = "202.38.93.111" })
|
||||||
|
val auth = File("doggy-auth.txt").readText()
|
||||||
|
|
||||||
|
val host = "http://202.38.93.111:10102/api/"
|
||||||
|
|
||||||
|
// Function to access api
|
||||||
|
fun get(api: String, body: String): String
|
||||||
|
{
|
||||||
|
val get = if (body == "") HttpGet(host + api)
|
||||||
|
else HttpPost(host + api).apply { entity = StringEntity(body) }
|
||||||
|
|
||||||
|
get.addHeader("authorization", auth)
|
||||||
|
get.addHeader("accept", "application/json, text/plain, */*")
|
||||||
|
get.addHeader("content-type", "application/json;charset=UTF-8")
|
||||||
|
val response = client.execute(get)
|
||||||
|
|
||||||
|
if (response.statusLine.statusCode != 200)
|
||||||
|
{
|
||||||
|
println("Error $api - Body: $body ; Status code: ${response.statusLine.statusCode}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val responseBody = EntityUtils.toString(response.entity, "UTF-8")
|
||||||
|
response.close()
|
||||||
|
return responseBody
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUser() = json.parse(User.serializer(), get("user", ""))
|
||||||
|
fun transfer(src: Int, dst: Int, amount: Int)
|
||||||
|
{
|
||||||
|
get("transfer", "{\"src\":$src,\"dst\":$dst,\"amount\":$amount}")
|
||||||
|
println("→ Transfer from $src to $dst, $amount")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create(credit: Boolean)
|
||||||
|
{
|
||||||
|
get("create", "{\"type\":\"${if (credit) "credit" else "debit"}\"}")
|
||||||
|
println("+ Created ${if (credit) "credit" else "debit"} card.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun eat(card: Int, log: Boolean = true)
|
||||||
|
{
|
||||||
|
get("eat", "{\"account\":$card}")
|
||||||
|
if (log) println("================ DAY ENDS ================")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each problem
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Backup session
|
||||||
|
val session = cookies.cookies.filter { it.name == "session" }[0].value
|
||||||
|
println("==============SESSION===============")
|
||||||
|
println(session)
|
||||||
|
println("================END=================")
|
||||||
|
sessionFile.writeText(session)
|
||||||
|
|
||||||
|
// Get today
|
||||||
|
val user = getUser()
|
||||||
|
|
||||||
|
// 后期可以不用四舍五入 bug 赚钱了
|
||||||
|
if (user.printSummary())
|
||||||
|
{
|
||||||
|
// 把所有储蓄卡转到卡 1
|
||||||
|
user.debits().forEach {
|
||||||
|
if (it.balance != 0) transfer(it.id, 1, it.balance)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 把所有债还了
|
||||||
|
user.credits().forEach {
|
||||||
|
if (it.balance != 0) transfer(1, it.id, it.balance)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化: 每 1 张信用卡添加 12 张储蓄卡
|
||||||
|
if (user.date == 1 && user.credits().isEmpty())
|
||||||
|
{
|
||||||
|
var idStart = 2 // 这一组的信用卡 ID
|
||||||
|
for (credit in 0..19)
|
||||||
|
{
|
||||||
|
create(true)
|
||||||
|
|
||||||
|
for (debit in 1..12)
|
||||||
|
{
|
||||||
|
create(false)
|
||||||
|
|
||||||
|
// 从信用卡给储蓄卡付款 167
|
||||||
|
transfer(idStart, idStart + debit, 167)
|
||||||
|
}
|
||||||
|
idStart += 13
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val debitThreshold = 10 + user.date / 10
|
||||||
|
val creditThreshold = 100
|
||||||
|
|
||||||
|
// 检查每张储蓄卡都差不多 167, 多赚的转到卡 1
|
||||||
|
user.debits().forEach {
|
||||||
|
if (it.balance > 167 + debitThreshold && it.id != 1)
|
||||||
|
{
|
||||||
|
Thread { transfer(it.id, 1, it.balance - 167) }.start()
|
||||||
|
Thread.sleep(100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 让信用卡都小于 -2098,多欠的的用卡 1 付
|
||||||
|
user.credits().forEach {
|
||||||
|
val transfer = it.balance - 2098 + creditThreshold
|
||||||
|
if (it.balance > 2098 && user.swap().balance > transfer) transfer(1, it.id, transfer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 吃!
|
||||||
|
eat(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后期模式, 开 15 个线程一起吃w
|
||||||
|
for (i in 0..14)
|
||||||
|
{
|
||||||
|
Thread { while (true) eat(1, false) }.start()
|
||||||
|
}
|
||||||
|
println("Rounding mode ended.")
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
when (readLine()!!.toLowerCase())
|
||||||
|
{
|
||||||
|
"stop" -> exitProcess(0)
|
||||||
|
"summary" -> getUser().printSummary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Account(
|
||||||
|
val balance: Int,
|
||||||
|
val id: Int,
|
||||||
|
val type: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class User(
|
||||||
|
val accounts: List<Account>,
|
||||||
|
val date: Int,
|
||||||
|
val flag: String?
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fun credits() = accounts.filter { it.type == "credit" }
|
||||||
|
fun debits() = accounts.filter { it.type == "debit" }
|
||||||
|
fun swap() = debits().find { it.id == 1 }!!
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print summary and check if it's ready to leave the rounding profit system.
|
||||||
|
*/
|
||||||
|
fun printSummary(): Boolean
|
||||||
|
{
|
||||||
|
val dSum = debits().map { it.balance }.sum()
|
||||||
|
val cSum = credits().map { it.balance }.sum()
|
||||||
|
val dd = debits().map { (it.balance * 0.003).roundToInt() }.sum()
|
||||||
|
val dc = -credits().map { (it.balance * 0.005).roundToInt() }.sum()
|
||||||
|
val de = -10
|
||||||
|
val sum = dd + dc + de
|
||||||
|
println("Summary - Total Balance: ${dSum - cSum} - DD: +$dd, DC: $dc, DE: $de, Sum: $sum")
|
||||||
|
|
||||||
|
// Check if it's ready to leave the rounding profit system
|
||||||
|
return ((dSum - cSum) * 0.003).roundToInt() > 20
|
||||||
|
}
|
||||||
|
}
|
||||||
+200
@@ -0,0 +1,200 @@
|
|||||||
|
package org.hydev.experiment
|
||||||
|
|
||||||
|
import org.apache.http.client.entity.UrlEncodedFormEntity
|
||||||
|
import org.apache.http.client.methods.HttpGet
|
||||||
|
import org.apache.http.client.methods.HttpPost
|
||||||
|
import org.apache.http.client.protocol.HttpClientContext
|
||||||
|
import org.apache.http.impl.client.BasicCookieStore
|
||||||
|
import org.apache.http.impl.client.HttpClients
|
||||||
|
import org.apache.http.impl.cookie.BasicClientCookie
|
||||||
|
import org.apache.http.message.BasicNameValuePair
|
||||||
|
import org.apache.http.util.EntityUtils
|
||||||
|
import org.hydev.logger.HyLoggerConfig
|
||||||
|
import org.hydev.logger.appenders.FileAppender
|
||||||
|
import java.awt.Robot
|
||||||
|
import java.awt.event.KeyEvent.*
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write a description for this class!
|
||||||
|
*
|
||||||
|
* @author HyDEV Team (https://github.com/HyDevelop)
|
||||||
|
* @author Hykilpikonna (https://github.com/hykilpikonna)
|
||||||
|
* @author Vanilla (https://github.com/VergeDX)
|
||||||
|
* @since 2020-11-02 15:51
|
||||||
|
*/
|
||||||
|
fun main(args: Array<String>)
|
||||||
|
{
|
||||||
|
// HyLogger
|
||||||
|
HyLoggerConfig.appenders.add(FileAppender("./logs", "ctf.log"))
|
||||||
|
HyLoggerConfig.installSysOut()
|
||||||
|
|
||||||
|
// Create http client
|
||||||
|
val builder = HttpClients.custom()
|
||||||
|
val context = HttpClientContext.create()
|
||||||
|
val cookies = BasicCookieStore()
|
||||||
|
context.cookieStore = cookies
|
||||||
|
builder.setDefaultCookieStore(cookies)
|
||||||
|
val client = builder.build()
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
val regex = """(?<=<p> \$).*(?=\$)""".toRegex()
|
||||||
|
val numberRegex = """(?<= )[0-9]*(?= 题)""".toRegex()
|
||||||
|
|
||||||
|
// CTF session
|
||||||
|
val sessionFile = File("session")
|
||||||
|
cookies.addCookie(BasicClientCookie("session", sessionFile.readText().replace("\n", ""))
|
||||||
|
.apply { domain = "202.38.93.111" })
|
||||||
|
|
||||||
|
// Clipboard
|
||||||
|
val clipboard = ClipboardTools()
|
||||||
|
|
||||||
|
// Robot: Keyboard control
|
||||||
|
val robot = Robot()
|
||||||
|
fun press(vararg events: Int)
|
||||||
|
{
|
||||||
|
events.forEach { robot.keyPress(it) }
|
||||||
|
robot.delay(100)
|
||||||
|
events.forEach { robot.keyRelease(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each problem
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Backup session
|
||||||
|
val session = cookies.cookies.filter { it.name == "session" }[0].value
|
||||||
|
println("==============SESSION===============")
|
||||||
|
println(session)
|
||||||
|
println("================END=================")
|
||||||
|
sessionFile.writeText(session)
|
||||||
|
|
||||||
|
// Get request
|
||||||
|
val get = HttpGet("http://202.38.93.111:10190/")
|
||||||
|
val response = client.execute(get)
|
||||||
|
val html = EntityUtils.toString(response.entity, "UTF-8")
|
||||||
|
val questionsRemaining = numberRegex.find(html)!!.value.toInt()
|
||||||
|
println("Questions remaining: $questionsRemaining")
|
||||||
|
val tex = regex.find(html)!!.value
|
||||||
|
response.close()
|
||||||
|
|
||||||
|
// Do the last one on the website by yourself
|
||||||
|
if (questionsRemaining == 1)
|
||||||
|
{
|
||||||
|
println("===============FINISH================")
|
||||||
|
println("Now copy the session and override your browser cookie, " +
|
||||||
|
"then complete the last question in your browser to get the flag.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tex to function, copy
|
||||||
|
val eq = toEquation(tex)
|
||||||
|
println(eq)
|
||||||
|
clipboard.clipboardContents = eq
|
||||||
|
|
||||||
|
// Robot: Auto paste and enter (META is the macOS command key. IF you're on Windows, change this to CONTROL)
|
||||||
|
press(VK_META, VK_V)
|
||||||
|
robot.delay(100)
|
||||||
|
press(VK_ENTER)
|
||||||
|
Thread.sleep(1000)
|
||||||
|
|
||||||
|
// Robot: Auto copy result
|
||||||
|
press(VK_UP)
|
||||||
|
robot.delay(100)
|
||||||
|
press(VK_META, VK_C) // META: same here :)
|
||||||
|
robot.delay(100)
|
||||||
|
press(VK_DOWN)
|
||||||
|
|
||||||
|
// Wait for clipboard
|
||||||
|
while (clipboard.getDouble() == null) { Thread.sleep(200) }
|
||||||
|
println("Clipboard received!")
|
||||||
|
val ans = clipboard.getDouble()
|
||||||
|
|
||||||
|
// Send response
|
||||||
|
val post = HttpPost("http://202.38.93.111:10190/submit")
|
||||||
|
post.addHeader("content-type", "application/x-www-form-urlencoded")
|
||||||
|
post.entity = UrlEncodedFormEntity(listOf(BasicNameValuePair("ans", String.format("%.6f", ans))), "UTF-8")
|
||||||
|
val result = client.execute(post)
|
||||||
|
result.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toEquation(originalTex: String): String
|
||||||
|
{
|
||||||
|
val tex = originalTex
|
||||||
|
.replace("\\left(", "(").replace("\\right)", ")").replace("\\,", " ")
|
||||||
|
.replace("{", "(").replace("}", ")")
|
||||||
|
.replace("\\", "")
|
||||||
|
.shortenSpaces()
|
||||||
|
return toEquationHelper(tex)
|
||||||
|
.replace("x (", "x * (").replace("x(", "x * (") // Fix implied multiplication error
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toEquationHelper(originalTex: String): String
|
||||||
|
{
|
||||||
|
var tex = originalTex
|
||||||
|
|
||||||
|
if (tex.startsWith("int_("))
|
||||||
|
{
|
||||||
|
tex = tex.substring(5, tex.length - 6)
|
||||||
|
val upper = tex.substring(0, tex.findBracket())
|
||||||
|
tex = tex.substring(upper.length + 3)
|
||||||
|
val lower = tex.substring(0, tex.findBracket())
|
||||||
|
tex = tex.substring(lower.length + 2)
|
||||||
|
return "integral(${toEquation(tex)},x,${toEquation(upper)},${toEquation(lower)})"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change fractions
|
||||||
|
while (tex.contains("frac("))
|
||||||
|
{
|
||||||
|
// frac(1)(2) -> (1)/(2)
|
||||||
|
val loc = tex.indexOf("frac(")
|
||||||
|
val endBrack = tex.findBracket(start = loc + 5)
|
||||||
|
tex = tex.substring(0, loc) + tex.substring(loc + 4, endBrack + 1) + "/" + tex.substring(endBrack + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tex
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the index of the end bracket
|
||||||
|
*
|
||||||
|
* @param bracket { or (
|
||||||
|
* @param start Start index
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun String.findBracket(bracket: Boolean = false, start: Int = 0): Int
|
||||||
|
{
|
||||||
|
val open = if (bracket) '{' else '('
|
||||||
|
val close = if (bracket) '}' else ')'
|
||||||
|
|
||||||
|
var level = 0
|
||||||
|
var i = start
|
||||||
|
|
||||||
|
while (i < length)
|
||||||
|
{
|
||||||
|
val c = this[i]
|
||||||
|
|
||||||
|
if (c == close)
|
||||||
|
{
|
||||||
|
if (level == 0) return i
|
||||||
|
else level--
|
||||||
|
}
|
||||||
|
if (c == open) level++;
|
||||||
|
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduce double spaces to single spaces
|
||||||
|
*
|
||||||
|
* @return Shortened string
|
||||||
|
*/
|
||||||
|
fun String.shortenSpaces(): String
|
||||||
|
{
|
||||||
|
var s = this
|
||||||
|
while (s.contains(" ")) s = s.replace(" ", " ")
|
||||||
|
return s
|
||||||
|
}
|
||||||
+132
@@ -0,0 +1,132 @@
|
|||||||
|
package org.hydev.experiment
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonConfiguration
|
||||||
|
import org.apache.http.client.methods.HttpPost
|
||||||
|
import org.apache.http.client.protocol.HttpClientContext
|
||||||
|
import org.apache.http.impl.client.BasicCookieStore
|
||||||
|
import org.apache.http.impl.client.HttpClients
|
||||||
|
import org.apache.http.util.EntityUtils
|
||||||
|
import org.hydev.logger.HyLoggerConfig
|
||||||
|
import org.hydev.logger.appenders.FileAppender
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URLEncoder
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write a description for this class!
|
||||||
|
*
|
||||||
|
* @author HyDEV Team (https://github.com/HyDevelop)
|
||||||
|
* @author Hykilpikonna (https://github.com/hykilpikonna)
|
||||||
|
* @author Vanilla (https://github.com/VergeDX)
|
||||||
|
* @since 2020-11-03 16:19
|
||||||
|
*/
|
||||||
|
fun main(args: Array<String>)
|
||||||
|
{
|
||||||
|
// Json
|
||||||
|
val json = Json(JsonConfiguration(isLenient = true))
|
||||||
|
|
||||||
|
// HyLogger
|
||||||
|
HyLoggerConfig.appenders.add(FileAppender("./logs", "ctf-mini-miner.log"))
|
||||||
|
HyLoggerConfig.installSysOut()
|
||||||
|
|
||||||
|
// Create http client
|
||||||
|
val builder = HttpClients.custom()
|
||||||
|
val context = HttpClientContext.create()
|
||||||
|
val cookies = BasicCookieStore()
|
||||||
|
context.cookieStore = cookies
|
||||||
|
builder.setDefaultCookieStore(cookies)
|
||||||
|
val client = builder.build()
|
||||||
|
|
||||||
|
// API stuff
|
||||||
|
val baseUrl = "http://localhost:8088/api/"
|
||||||
|
val token = File("mini-miner-token.txt").readText().replace("\n", "")
|
||||||
|
|
||||||
|
fun post(api: String, params: String): String
|
||||||
|
{
|
||||||
|
// Create post
|
||||||
|
val url = "$baseUrl$api?token=${token.urlEncode()}$params"
|
||||||
|
val post = HttpPost(url).apply {
|
||||||
|
addHeader("accept", "*/*")
|
||||||
|
addHeader("content-type", "application/json;charset=UTF-8")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute
|
||||||
|
val response = client.execute(post)
|
||||||
|
val responseBody = EntityUtils.toString(response.entity, "UTF-8")
|
||||||
|
response.close()
|
||||||
|
|
||||||
|
// Error
|
||||||
|
if (response.statusLine.statusCode != 200)
|
||||||
|
{
|
||||||
|
println("Error $api - Params: $params ; Status code: ${response.statusLine.statusCode} ; Response body: $responseBody")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return body
|
||||||
|
return responseBody
|
||||||
|
}
|
||||||
|
fun state() = json.parse(StateReturn.serializer(), post("state", "&x=0&y=0"))
|
||||||
|
fun reset() = json.parse(ResetReturn.serializer(), post("reset", ""))
|
||||||
|
fun damage(x: Int, y: Int) = json.parse(DamageReturn.serializer(), post("damage", "&x=$x&y=$y&material=OBSIDIAN"))
|
||||||
|
|
||||||
|
|
||||||
|
// Actual code begins
|
||||||
|
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Reset and get current state
|
||||||
|
println(reset())
|
||||||
|
val state = state()
|
||||||
|
|
||||||
|
// Find flag
|
||||||
|
var flagX = 0
|
||||||
|
var flagY = 0
|
||||||
|
for (x in 0..state.materials.size)
|
||||||
|
{
|
||||||
|
if (state.materials[x].contains("FLAG"))
|
||||||
|
{
|
||||||
|
flagX = x
|
||||||
|
flagY = state.materials[x].indexOf("FLAG")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println("$flagX,$flagY")
|
||||||
|
|
||||||
|
// Destroy block, wait for it to complete (long = 5s)
|
||||||
|
damage(flagX, flagY)
|
||||||
|
Thread.sleep(5500)
|
||||||
|
|
||||||
|
// Destroy air, have roughly 3s until it checks the flag again
|
||||||
|
Thread {
|
||||||
|
val result = damage(flagX, flagY)
|
||||||
|
println(result)
|
||||||
|
}.start()
|
||||||
|
|
||||||
|
Thread.sleep(500)
|
||||||
|
reset() // Reset the flag block
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ResetReturn(
|
||||||
|
val expiration: String,
|
||||||
|
val user: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class StateReturn(
|
||||||
|
val materials: List<List<String>>,
|
||||||
|
val min: List<Int>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DamageReturn(
|
||||||
|
val dropped: String,
|
||||||
|
val flag: String
|
||||||
|
)
|
||||||
|
|
||||||
|
fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8")
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package org.hydev.experiment
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat.QR_CODE
|
||||||
|
import com.google.zxing.BinaryBitmap
|
||||||
|
import com.google.zxing.DecodeHintType.*
|
||||||
|
import com.google.zxing.client.j2se.BufferedImageLuminanceSource
|
||||||
|
import com.google.zxing.common.BitSource
|
||||||
|
import com.google.zxing.common.GlobalHistogramBinarizer
|
||||||
|
import com.google.zxing.multi.GenericMultipleBarcodeReader
|
||||||
|
import com.google.zxing.qrcode.QRCodeReader
|
||||||
|
import org.apache.commons.io.FileUtils
|
||||||
|
import java.io.File
|
||||||
|
import java.lang.System.err
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
// 这个是要改 ZXing 源码才会把解析的 byte[] 加进来啦w
|
||||||
|
var parsedBytes = byteArrayOf();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Write a description for this class!
|
||||||
|
*
|
||||||
|
* @author HyDEV Team (https://github.com/HyDevelop)
|
||||||
|
* @author Hykilpikonna (https://github.com/hykilpikonna)
|
||||||
|
* @author Vanilla (https://github.com/VergeDX)
|
||||||
|
* @since 2020-11-05 18:27
|
||||||
|
*/
|
||||||
|
fun main(args: Array<String>)
|
||||||
|
{
|
||||||
|
var rawBytes = byteArrayOf()
|
||||||
|
var utfBytes = byteArrayOf()
|
||||||
|
var iso8859Bytes = byteArrayOf()
|
||||||
|
|
||||||
|
File("/Users/hykilpikonna/Downloads/CTF/qr-frames").listFiles()!!.sorted().forEach {
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
val source = BufferedImageLuminanceSource(ImageIO.read(it))
|
||||||
|
val bitmap = BinaryBitmap(GlobalHistogramBinarizer(source))
|
||||||
|
val reader = GenericMultipleBarcodeReader(QRCodeReader())
|
||||||
|
val hints = mapOf(TRY_HARDER to true, POSSIBLE_FORMATS to QR_CODE, PURE_BARCODE to true)
|
||||||
|
|
||||||
|
val result = reader.decodeMultiple(bitmap, hints)[0]
|
||||||
|
|
||||||
|
rawBytes += result.rawBytes
|
||||||
|
utfBytes += result.text.toByteArray(Charset.forName("UTF-16"))
|
||||||
|
iso8859Bytes += result.text.toByteArray(Charset.forName("ISO-8859-1"))
|
||||||
|
}
|
||||||
|
catch (e: Exception)
|
||||||
|
{
|
||||||
|
err.println(it)
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val bits = BitSource(rawBytes)
|
||||||
|
val readBytes = ByteArray(rawBytes.size)
|
||||||
|
for (i in rawBytes.indices)
|
||||||
|
{
|
||||||
|
readBytes[i] = bits.readBits(8).toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtils.writeByteArrayToFile(File("./qr_bytes_raw_processed"), parsedBytes)
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package org.hydev.experiment
|
||||||
|
|
||||||
|
import java.awt.Toolkit
|
||||||
|
import java.awt.datatransfer.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://www.javapractices.com/topic/TopicAction.do?Id=82
|
||||||
|
*/
|
||||||
|
class ClipboardTools : ClipboardOwner
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Empty implementation of the ClipboardOwner interface.
|
||||||
|
*/
|
||||||
|
override fun lostOwnership(clipboard: Clipboard, contents: Transferable) {}
|
||||||
|
|
||||||
|
fun getDouble() = clipboardContents!!.replace("−", "-").toDoubleOrNull();
|
||||||
|
fun getInt() = clipboardContents!!.replace("−", "-").toIntOrNull();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get and set the clipboard contents
|
||||||
|
*/
|
||||||
|
var clipboardContents: String?
|
||||||
|
get()
|
||||||
|
{
|
||||||
|
var result = ""
|
||||||
|
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
|
||||||
|
val contents = clipboard.getContents(null)
|
||||||
|
val hasTransferableText = contents != null && contents.isDataFlavorSupported(DataFlavor.stringFlavor)
|
||||||
|
if (hasTransferableText)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = contents!!.getTransferData(DataFlavor.stringFlavor) as String
|
||||||
|
}
|
||||||
|
catch (ex: Exception)
|
||||||
|
{
|
||||||
|
ex.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
set(string)
|
||||||
|
{
|
||||||
|
val stringSelection = StringSelection(string)
|
||||||
|
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
|
||||||
|
clipboard.setContents(stringSelection, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
## 14: 来自未来的 ~~D-Mail~~
|
## 14: 来自未来的 ~~D-Mail~~
|
||||||
|
|
||||||
|
[Kotlin 源码](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTFQR.kt)
|
||||||
|
|
||||||
(会有 3020 的考古队看到这个嘛w?:thinking:
|
(会有 3020 的考古队看到这个嘛w?:thinking:
|
||||||
|
|
||||||
1. 把 QR **解析**成 `byte[]` 然后写到文件里(和 rawBytes 不一样哦!
|
1. 把 QR **解析**成 `byte[]` 然后写到文件里(和 rawBytes 不一样哦!
|
||||||
@@ -51,6 +53,8 @@ Python 的库试过的: zbar 装不上,qrtools 不能用来解析,pyzbar 很
|
|||||||
|
|
||||||
## 15. 狗狗银行 🐶🏦
|
## 15. 狗狗银行 🐶🏦
|
||||||
|
|
||||||
|
[Kotlin 源码](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTFDoggyBank.kt)
|
||||||
|
|
||||||
### 数学方面的
|
### 数学方面的
|
||||||
|
|
||||||
1. 信用卡欠 2099 的话每天的利息是 10.49(10),实际利率是 4.99%
|
1. 信用卡欠 2099 的话每天的利息是 10.49(10),实际利率是 4.99%
|
||||||
@@ -83,6 +87,8 @@ Python 的库试过的: zbar 装不上,qrtools 不能用来解析,pyzbar 很
|
|||||||
|
|
||||||
## 16. ∫(超基础的数理模拟器)dx
|
## 16. ∫(超基础的数理模拟器)dx
|
||||||
|
|
||||||
|
[Kotlin 源码](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTFIntegrals.kt)
|
||||||
|
|
||||||
虽然不是最高效的解但是视觉效果超厉害的!!
|
虽然不是最高效的解但是视觉效果超厉害的!!
|
||||||
**视频链接:** [ビリビリ](https://www.bilibili.com/video/BV16a411c7jN/) | [YouTube](https://youtu.be/8L2TkLmXngQ)
|
**视频链接:** [ビリビリ](https://www.bilibili.com/video/BV16a411c7jN/) | [YouTube](https://youtu.be/8L2TkLmXngQ)
|
||||||
|
|
||||||
@@ -107,6 +113,8 @@ Sage 看了下但是不知道怎样在程序里面控制w
|
|||||||
|
|
||||||
## 19. 超恶臭的数字论证器 (确信)
|
## 19. 超恶臭的数字论证器 (确信)
|
||||||
|
|
||||||
|
[Kotlin 源码 (是最乱的一个 ;-;)](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTF114514.kt)
|
||||||
|
|
||||||
原来官方解法那么简单哇w
|
原来官方解法那么简单哇w
|
||||||
代码短 20 倍了!!!(╯‵□′)╯︵┻━┻
|
代码短 20 倍了!!!(╯‵□′)╯︵┻━┻
|
||||||
|
|
||||||
@@ -140,6 +148,8 @@ Sage 看了下但是不知道怎样在程序里面控制w
|
|||||||
|
|
||||||
## 31. 超迷你的挖矿模拟器 ⛏️
|
## 31. 超迷你的挖矿模拟器 ⛏️
|
||||||
|
|
||||||
|
[Kotlin 源码](./KotlinProject/src/main/kotlin/org/hydev/experiment/CTFMiniMiner.kt)
|
||||||
|
|
||||||
1. 挖掉 Flag 位置(1,1)的方块w(5s
|
1. 挖掉 Flag 位置(1,1)的方块w(5s
|
||||||
2. 开始挖 Flag 位置的空气,
|
2. 开始挖 Flag 位置的空气,
|
||||||
这个时候服务器检测到空气所以就执行可以掉落物品的代码w
|
这个时候服务器检测到空气所以就执行可以掉落物品的代码w
|
||||||
|
|||||||
Reference in New Issue
Block a user