AuthorMr R.

Mount docker volume as same user as on host machine

docker containers often run as the root user (uid = 0, guid = 0). Files that the users generates are therefore also owned by the root user.

By creating an extra user on the docker system, and giving that user the same uid and guid as the user on you host system you will be able to modify your files without the need to be root on you host machine.

The following assumes you created an additional user in your docker container, and that it got 1000 for uid and guid.

#!/bin/bash

# Mr. R
# 06-2020

args=$@
cmd="builder.sh ${args}"

# current working directory is a volume mount to something on the host system.
# Therefore stat -c will provide the uid and gid of the host user.
# setting this uid and gid for the container user results in files written to the
# volume as host user.
usr=`id -nu 1000`
grp=`id -ng 1000`
groupmod -g $(stat -c "%g" .) $grp
usermod -u $(stat -c "%u" .) -g $(stat -c "%g" .) $usr

# Force all volume mounts to be of the appuser!
chown -R ${usr}:${grp} ${WORKDIR}

# If nothing given, start a shell, else run the builder script with arguments.
if [ "x${args}x" == "xx" ]; then
  cmd="/bin/bash"
fi

su -m -c "PATH=${PATH}; ${cmd}" ${usr}

Restore a deleted file in git

Git is your lifesaver if you have deleted a file somewhere in the past and committed that change.

Due to the nature of Git that file is not gone, but just hidden.
You can retrieve that file by using “checkout”.

You should select the commit before the file got deleted or you’ll see an:

error: pathspec '<your-file-to-retrieve>' did not match any file(s) known to git.

So, suppose your commit is at 48b8bc and you want to retrieve some-file.txt:

git checkout 48b8bc -- some-file.txt

Now the file you were looking for should be in your new files when checking it with: “git status”.

Ping addresses on a subnet (no nmap)

If you are on a remote host, and you have not the rights to install any other software, then this might come in handy.

Normally I would use “nmap” to scan for other devices on the network, but if that is not available and “ping” is, then this can also discover online devices on the network, assuming they are pingable (ICMP enabled).

#!/bin/bash
# Ping devices on a subnet

SUBNET=${1:-"192.168.2"}

function main()
{
  for i in $SUBNET.{1..254}
  do
    check_alive $i &
  done

  # Sleep to not put shell inbetween
  sleep 1
  exit 0
}

function check_alive()
{
  ping -c 1 $1 > /dev/null
  [ $? -eq 0 ] && echo -e "$i\t UP"
}

main $@

The output will look like the following:

⇒  ./ping-it.sh 192.168.2
192.168.2.69	 UP
192.168.2.62	 UP
192.168.2.254	 UP
192.168.2.14	 UP
192.168.2.65	 UP
192.168.2.182	 UP
192.168.2.25	 UP
192.168.2.200	 UP
192.168.2.210	 UP
192.168.2.190	 UP

Meaning of “man” numbers (e.g. mkfifo(3)

I always forget what the number after the man pages means.
For example mkfifo(3) (https://linux.die.net/man/3/mkfifo).

This post helps me (and you) to not forget 🙂

MANUAL SECTIONS
    The standard sections of the manual include:

    1      User Commands
    2      System Calls
    3      C Library Functions
    4      Devices and Special Files
    5      File Formats and Conventions
    6      Games et. al.
    7      Miscellanea
    8      System Administration tools and Daemons

    Distributions customize the manual section to their specifics,
    which often include additional sections.

Note: I found out that “man” has a man page of itself. So this is not really necessary anymore. I keep it here for others to find though.

But remember:

$ man man

Python3 custom logging module

I made a logging module based on the logging module of python itself.

It prints to file, and also in the console, and rotates the file automatically on a new start.

# Use it in your other modules as:
  # from Log import Log
  # logger = Log(__name__)

import logging
from logging import handlers
import os

LOG_LEVEL = logging.DEBUG

logger = logging.getLogger()
logger.setLevel(LOG_LEVEL)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

ch = logging.StreamHandler()
ch.setLevel(LOG_LEVEL)
ch.setFormatter(formatter)
logger.addHandler(ch)

filename = "./log/log.txt"
should_roll_over = os.path.isfile(filename)
rfh = handlers.RotatingFileHandler(filename, maxBytes=5 * 1000 * 1000, backupCount=20)
if should_roll_over:
  rfh.doRollover()
rfh.setLevel(LOG_LEVEL)
rfh.setFormatter(formatter)
logger.addHandler(rfh)


class Log():
  def __init__(self, name):
    self.logger = logging.getLogger(name)

    self.info(f"Instantiated logger for {name}")

  def critical(self, msg):
    self.logger.critical(msg)

  def fatal(self, msg):
    self.logger.fatal(msg)

  def error(self, msg):
    self.logger.error(msg)

  def warning(self, msg):
    self.logger.warning(msg)

  def warn(self, msg):
    self.logger.warn(msg)

  def info(self, msg):
    self.logger.info(msg)

  def debug(self, msg):
    self.logger.debug(msg)

Swego: Go answer to Python’s SimpleHTTPServer

SimpleHTTPserver of Python is an easy way to create a HTTP Server in a directory:

python -m SimpleHTTPServer 80

Also an NGINX instance with Directory Listing enabled is another possibility.

But now we also have Swego, written in Go, fully packed with cool features. It came on my radar one year ago, and I forgot the name of this project. Up until know it was lost, but recently I re-discovered it.

Features:

  • HTTPS (auto generate certificate / key if no certificate / key specified)
  • Directory listing
  • Define a private folder with basic authentication
  • Upload multiple files
  • Download file as an encrypted zip (password: infected)
  • Download folder with a zip
  • Embedded files
  • Run embedded binary written in C# (only available on Windows)
  • Create a folder from the browser
  • Ability to execute embedded binary
  • Feature for search and replace (for fill the IP address in reverse shell for example)
  • Generate one-liners to download and execute a embedded file
  • Config file.
  • Auto generate random certificate for TLS

Especially the search and replace for text based files can be very useful for pentesters.

You can find the repository here: https://github.com/nodauf/Swego

Completely wipe Bash history

Clearing out your bash history can be quite a hassle as it keeps a copy in the memory that will be flushed at the moment you log out. There is a workaround:

cat /dev/null > ~/.bash_history && history -c && exit

After this command the history is wiped.
I use this when creating binary copies of the filesystem when I do not want to include any history (Create bitwise copy of EMMC/SD/HDD/SDD over the network (backup using ssh pipe)).

Source: https://askubuntu.com/a/192001

Create bitwise copy of EMMC/SD/HDD/SDD over the network (backup using ssh pipe)

It can be convenient to make a bitwise copy. For example to place the contents of 1 embedded board (i.e. Beaglebone) to another embedded board.

If the device to copy is also the storage device that holds the OS, then boot from another device, for example a “Try Ubuntu” usb drive.

We stream the data over the network, because the devices themselves mostly have no space to place the image somewhere on the that device.

Assumption is that you have a working ssh server on the device you want to copy to.

The perform the following:

  1. Find the correct device to make a copy from. So the whole device, not the partition.
    In my case it is “/dev/mmcblk0” so without the partition indicator -> “p1”.
  2. Find the ip adress of the device to copy to (or use hostname)

To create an image:

> sudo cat /dev/mmcblk0 | ssh <user>@<ip-adress> "gzip ~/image.gz"

After the operation is done you have a bitwise copy gzipped on your <ip-address> machine in the home directory of the <user>

To deploy an earlier created image back to the device, from the device to deploy to (Make sure you booted from another device than we are copying to):

> ssh <user>@<ip-address> "gzip -dc ~/image.gz" | dd of=/dev/mmcblk0 status=progress

Wipe bash history!

If you were ever to create an image of your OS for example, but do not want to include your history.

It also wipes the history still in the memory.

cat /dev/null > ~/.bash_history && history -c && exit

Also, if you don’t even want that your command ends up in your bash history in the first place, add a space at the start of you command and it will not be in your bash history!

> echo "inhistory" > blaa
>   echo "notinhistory" > blaa  #notice the space

The “notinhistory” is not in the history file:

> history | tail -n1
10438  echo "inhistory" > blaa

Bash script template

Whenever writing a script you might want to enable some options depending on what you provide on the CLI.

I’ve created a bash script template to getting started quick with a bash script. You can specify full options or the short ones with arguments or without.

#!/bin/bash
# Version 2.0
# Script template

set -eou pipefail

DO_OPT_A=false
DO_OPT_B=false

# directory of the script, can be useful for locating files which are next to the script.
THISDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

function main() {
  check_root

  do_parse_opts $@

  [[ ${DO_OPT_A}   = true ]] && check_opt_a_prerequisites
  [[ ${DO_OPT_B}   = true ]] && check_opt_b_prerequisites

  print_info "Checks OK, you have 2s to abort now!"
  sleep 2
  echo ""

  [[ ${DO_OPT_A} = true ]] && {
    do_opt_a_function
  }

  [[ ${DO_OPT_B} = true ]] && {
    do_opt_b_function
  }
}

function show_help() {
  echo "Scripting template :)"

  echo "Usage:"
  echo "    $0 [-a/--option_a] [-b/--option_b <arg>]"

  echo "        *  [-h/--help]      Print this help"
  echo "        *  [-a/--option_a]  Perform option A"
  echo "        *  [-b/--option_b <arg>]  Perform option B with argument"
  echo ""
  exit 1
}

function do_parse_opts() {
  # convert long options to shorts
  for arg in "$@"; do
    shift
    case "$arg" in
        "--help")       set -- "$@" "-h" ;;
        "--option_a")   set -- "$@" "-a" ;;
        "--option_b")   set -- "$@" "-b" ;;
        *)              set -- "$@" "$arg"
    esac
  done

  OPTIND=1 # Reset in case getopts has been used previously in the shell.
  while getopts "hab:" opt; do
      case "$opt" in
      h)
          show_help
          exit 0
          ;;
      a)  DO_OPT_A=true
          ;;
      b)  DO_OPT_B=true
          BARG=$OPTARG
          ;;
      esac
  done

  shift $((OPTIND-1))

  [ "${1:-}" = "--" ] && shift

  print_info "DO_OPT_A    = $DO_OPT_A"
  print_info "DO_OPT_B    = $DO_OPT_B"

  [[ ${DO_OPT_A} = false ]] && [[ ${DO_OPT_B} = false ]] && {
    print_info "Hey! Your provided no options, this might help:"
    echo ""
    show_help
  }

  echo ""
}

function check_root() {
    [[ $EUID -ne 0 ]] && {
        echo "[ERROR]     This script must be run as root"
        show_help
    }
}

function check_opt_a_prerequisites() {
    print_info "Checking option A prerequisites"
    sleep 1
    print_ok
}

function check_opt_b_prerequisites() {
    print_info "Checking option B prerequisites"
    sleep 1
    print_ok
}


function do_opt_a_function() {
    print_info "Performing A"
    sleep 1
    print_ok
}


function do_opt_b_function() {
    print_info "Performing B, with arg: ${BARG}"
    sleep 1
    print_ok
}


function print_ok() {
  echo "[OK]"
}

function print_info() {
  echo "[INFO]      $1..."
}

function print_error() {
  echo "[ERROR]     $1"
  exit 1
}


main $@

print_info "All done!"
echo "[OK]"

© 2025 Roholt

Thema door Anders NorénOmhoog ↑