Skip to content

Comments

Add support for UPX files#731

Merged
egibs merged 9 commits intochainguard-dev:mainfrom
egibs:add-upx-support
Dec 30, 2024
Merged

Add support for UPX files#731
egibs merged 9 commits intochainguard-dev:mainfrom
egibs:add-upx-support

Conversation

@egibs
Copy link
Member

@egibs egibs commented Dec 19, 2024

Closes: #197

Now that we've been encountering UPX binaries in packages, it makes sense to add support for scanning these files.

The main issue with this is that UPX has to be installed, but otherwise scanning is as easy as copying the file into our temporary scan directory and then running upx -d.

Before:

🔎 Scanning "~/Downloads/trino/usr/lib/trino/bin/linux-arm64/launcher"
├─ 🟡 ~/Downloads/trino/usr/lib/trino/bin/linux-arm64/launcher [MEDIUM]
│     ≡ anti-static [MEDIUM]
│       🟡 elf/content — Obfuscated ELF binary (missing symbols)
│       🟡 elf/entropy — high entropy footer in ELF binary (>7.4)
│       🟡 elf/header — high entropy ELF header (>7)
│       🟡 elf/multiple — multiple ELF binaries within an ELF binary: $elf_head
│       🟡 packer/upx — Linux ELF binary packed with UPX: This file is packed, UPX!, executable packer
│     ≡ command & control [LOW]
│       🔵 addr/url — binary contains hardcoded URL: http://upx.sf.net
│     ≡ cryptography [LOW]
│       🔵 aes — Supports AES (Advanced Encryption Standard)
│     ≡ filesystem [MEDIUM]
│       🟡 path/users — references path within /Users: /Users/martin/go/pkg
│       🟡 proc/self_exe — gets executable associated to this process: /proc/self/exe
│     ≡ networking [LOW]
│       🔵 dns/txt — Uses DNS TXT (text) records: dns
│       🔵 url/embedded — contains embedded HTTP URLs: http://upx.sf.net
│

After:

🔎 Scanning "~/Downloads/trino/usr/lib/trino/bin/linux-arm64/launcher"
├─ 🟡 ~/Downloads/trino/usr/lib/trino/bin/linux-arm64/launcher ∴ /launcher [MEDIUM]
│     ≡ collection [MEDIUM]
│       🟡 archives/zip — Works with zip files: archive/zip
│     ≡ command & control [MEDIUM]
│       🟡 addr/ip — mentions an IP and port: lIp, lookupPort, parsePort
│       🔵 addr/url — binary contains hardcoded URL:
│          http://AvestanBengaliBrailleCypriotDeseretElbasanElymaicGranthaHanunooKannadaMakasarMandaicMarchenMultaniMyanmarOsmanya…
│       🔵 tool_transfer/arch — references a specific architecture: amd64, arm64, http://
│       🔵 tool_transfer/os — references a specific operating system: Linux, http://
│     ≡ credential [LOW]
│       🔵 password — references a 'password': UserPassword, passwordSet
│       🔵 ssl/private_key — References private keys: privateKey
│     ≡ cryptography [LOW]
│       🔵 aes — Supports AES (Advanced Encryption Standard): crypto/aes
│       🔵 ecdsa — Uses the Go crypto/ecdsa library
│       🔵 public_key — references a 'public key': PublicKey, publicKey
│       🔵 tls — tls: crypto/tls
│     ≡ data [LOW]
│       🔵 compression/gzip — works with gzip files
│       🔵 encoding/base64 — Supports base64 encoded strings
│     ≡ discovery [LOW]
│       🔵 system/cpu — gets number of processors: nproc
│       🔵 system/hostname — get computer host name: /proc/sys/kernel/hostname
│       🔵 system/platform — system identification: syscall.Uname
│     ≡ execution [MEDIUM]
│       🔵 plugin — references a 'plugin': bytestringconfigpluginfunc, pluginpath, pluginversion
│       🟡 program — executes external programs: ).CombinedOutput, exec.(*Cmd).Run
│     ≡ filesystem [MEDIUM]
│       🔵 directory/create — creates directories: mkdir
│       🔵 directory/remove — Uses libc functions to remove directories: Rmdir
│       🔵 file/delete — deletes files: unlinkat
│       🔵 file/open — opens files: openFile
│       🔵 file/read — reads files: ReadFile, os.(*File).Read
│       🔵 link_read — read value of a symbolic link: readlinkat
│       🔵 lock_update — apply or remove an advisory lock on a file: flock
│       🔵 path/etc — path reference within /etc:
│          /etc/apache/mime.typesidna, /etc/hostsgetsockoptnetlinkribsetsock, /etc/httpd/conf/mime.typessegment, /etc/mime.types, …
│       🟡 path/etc_hosts — references /etc/hosts
│       🔵 path/etc_resolv.conf — accesses DNS resolver configuration: /etc/resolv.conf
│       🟡 path/users — references path within /Users:
│          /Users/martin/go/pkg/mod/github.com/fatih/color, /Users/martin/go/pkg/mod/github.com/mattn/go-isatty, /Users/martin/go/…
│       🔵 path/var — path reference within /var: /var/log/launcher.log, /var/log/server.log, /var/run/launcher.pidfailed
│       🟡 permission/chown — Changes file ownership: Chown
│       🟡 permission/modify — modifies file permissions: Chmod, chmod
│     ≡ networking [MEDIUM]
│       🔵 dns — Uses DNS (Domain Name Service): CNAMEResource, SetEDNS0, dnsmessage
│       🔵 dns/servers — Examines local DNS servers: CNAMEResource
│       🔵 dns/txt — Uses DNS TXT (text) records: dns
│       🔵 http/auth — makes HTTP requests with basic authentication: www-authenticate
│       🟡 http/post — submits content to websites: HTTP, POST, http
│       🔵 http/proxy — discover proxy address via environment: HTTPS_PROXY, HTTP_PROXY
│       🔵 http/request — makes HTTP requests: User-Agent
│       🟡 ip/addr — mentions an 'IP address': ipAddr
│       🟡 ip/host_port — connects to an arbitrary hostname:port: hostunknown port
│       🟡 ip/parse — parses IP address (IPv4 or IPv6): IsLinkLocalUnicast
│       🔵 resolve/hostname — resolve network host name to IP address: net.hostLookup
│       🟡 socket/listen — listen on a socket: accept
│       🔵 socket/local_addr — get local address of connected socket: getsockname
│       🔵 socket/peer_address — get peer address of connected socket: getpeername
│       🔵 socket/receive — receive a message from a socket: recvfrom
│       🔵 socket/send — send a message to a socket: sendto
│       🟡 tcp/connect — connects to a TCP port: dialTCP
│       🔵 udp/receive — Listens for UDP responses: ReadFromUDP
│       🔵 udp/send — Sends UDP packets: DialUDP, WriteMsgUDP
│       🔵 url/embedded — contains embedded HTTP URLs: http://AvestanBengaliBrailleCypriotDeseretElbasanElymaicGranthaHanunooKa
│       🔵 url/parse — Handles URL strings: RequestURI
│       🟡 url/request — requests resources via URL: net/url
│     ≡ operating-system [LOW]
│       🔵 fd/sendfile — transfer data between file descriptors: sendfile, syscall.Sendfile
│       🔵 kernel/netlink — communicate with kernel services: netlink
│     ≡ persistence [MEDIUM]
│       🟡 daemon — Run as a background daemon
│       🟡 pid_file — pid file, likely DIY daemon: /var/run/launcher.pid, LockablePidFile, lockablePidFile, pidFile
│     ≡ process [LOW]
│       🔵 groups_set — set group access list: setgroups
│

Verification that we're not just decompressing the source file:

time=2024-12-19T08:52:48.486-06:00 level=DEBUG source=.../repos/chainguard-dev/malcontent/pkg/archive/archive.go:100 msg="creating temp dir" path=~/Downloads/trino/usr/lib/trino/bin/linux-arm64/launcher
time=2024-12-19T08:52:48.487-06:00 level=DEBUG source=.../repos/chainguard-dev/malcontent/pkg/archive/upx.go:34 msg="extracting upx" dir=/var/folders/n6/xxn5d2zd3l1gghpx_7qppzs00000gn/T/launcher893271144 file=~/Downloads/trino/usr/lib/trino/bin/linux-arm64/launcher

Signed-off-by: egibs <20933572+egibs@users.noreply.github.com>
@egibs egibs requested a review from tstromberg December 19, 2024 14:55
Signed-off-by: egibs <20933572+egibs@users.noreply.github.com>
Signed-off-by: egibs <20933572+egibs@users.noreply.github.com>
Signed-off-by: egibs <20933572+egibs@users.noreply.github.com>
Signed-off-by: egibs <20933572+egibs@users.noreply.github.com>
Signed-off-by: egibs <20933572+egibs@users.noreply.github.com>
"RiskScore": 4,
"RiskLevel": "CRITICAL"
},
"/__min__c.~": {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since UPX scans will result in two reports, we'll need to use JSON to maintain deterministic ordering.

Signed-off-by: egibs <20933572+egibs@users.noreply.github.com>
@egibs egibs requested a review from tstromberg December 19, 2024 21:01
@stevebeattie
Copy link
Member

One concern I had was the possibility that upx -d would end up transferring code execution into the wrapping upx code embedded in the compressed file (which would be undesired risky behavior), but from a cursory inspection under strace and of the upx source code, it does not seem to do that.

Otherwise this PR LGTM.

@stevebeattie stevebeattie self-requested a review December 30, 2024 20:28
@egibs egibs merged commit bbd5349 into chainguard-dev:main Dec 30, 2024
8 checks passed
@egibs egibs deleted the add-upx-support branch January 17, 2025 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support transparent decompression of UPX'd binaries

3 participants