• How to make a bootable USB with GRUB2 and ISO

    Do you have multiple ISO files to install, with quite enough storage of USB stick? You’ll want to install all of them with a single USB stick. Here’s how.

    Formatting USB disk

    First, plug in your USB stick and find it from your Linux machine:

    $ sudo fdisk -l
    Disk /dev/sda: 20 GiB, 21474836480 bytes, 41943040 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x4d149927
    
    Device     Boot    Start      End  Sectors  Size Id Type
    /dev/sda1  *        2048 39845887 39843840   19G 83 Linux
    /dev/sda2       39847934 41940991  2093058 1022M  5 Extended
    /dev/sda5       39847936 41940991  2093056 1022M 82 Linux swap / Solaris
    
    
    Disk /dev/sdb: 14.6 GiB, 15664676864 bytes, 30595072 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: gpt
    Disk identifier: 4788154A-7BD2-4A06-945B-5980E828C8C5
    
    Device      Start      End  Sectors  Size Type
    /dev/sdb1      40   409639   409600  200M EFI System
    /dev/sdb2  411648 30593023 30181376 14.4G Microsoft basic data
    

    In my case, it’s /dev/sdb. Let’s format it with fdisk. When you run fdisk /dev/sdb, you can print help menu:

    $ sudo fdisk /dev/sdb
    
    Welcome to fdisk (util-linux 2.27.1).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.
    
    
    Command (m for help): m
    
    Help:
    
      Generic
       d   delete a partition
       F   list free unpartitioned space
       l   list known partition types
       n   add a new partition
       p   print the partition table
       t   change a partition type
       v   verify the partition table
       i   print information about a partition
    
      Misc
       m   print this menu
       x   extra functionality (experts only)
    
      Script
       I   load disk layout from sfdisk script file
       O   dump disk layout to sfdisk script file
    
      Save & Exit
       w   write table to disk and exit
       q   quit without saving changes
    
      Create a new label
       g   create a new empty GPT partition table
       G   create a new empty SGI (IRIX) partition table
       o   create a new empty DOS partition table
       s   create a new empty Sun partition table
    

    Now we can start!

    $ sudo fdisk /dev/sdb
    
    Welcome to fdisk (util-linux 2.27.1).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.
    
    
    Command (m for help): o
    Created a new DOS disklabel with disk identifier 0x8c9faeb0.
    
    Command (m for help): n
    Partition type
       p   primary (0 primary, 0 extended, 4 free)
       e   extended (container for logical partitions)
    Select (default p):
    
    Using default response p.
    Partition number (1-4, default 1):
    First sector (2048-30595071, default 2048):
    Last sector, +sectors or +size{K,M,G,T,P} (2048-30595071, default 30595071):
    
    Created a new partition 1 of type 'Linux' and of size 14.6 GiB.
    
    Command (m for help): t
    Selected partition 1
    Partition type (type L to list all types): c
    Changed type of partition 'Linux' to 'W95 FAT32 (LBA)'.
    
    Command (m for help): a
    Selected partition 1
    The bootable flag on partition 1 is enabled now.
    
    Command (m for help): w
    The partition table has been altered.
    Calling ioctl() to re-read partition table.
    Syncing disks.
    

    We’ve just created one bootable FAT partition, and that’ll be /dev/sdb1. Let’s create an MS-DOS filesystem in it. This will take a while.

    $ sudo mkfs.vfat -F 32 /dev/sdb1
    mkfs.fat 3.0.28 (2015-05-16)
    

    Now you can mount that partition and we’re ready to install GRUB2 in it.

    sudo mkdir /mnt/usb
    sudo mount /dev/sdb1 /mnt/usb
    

    Installing GRUB2

    Since we’re installing GRUB2 into USB stick, we specify --removable flag. Also specify --boot-directory so that GRUB2 is installed to there instead of /boot/grub.

    $ sudo grub-install --removable --boot-directory=/mnt/usb/boot /dev/sdb
    Installing for i386-pc platform.
    Installation finished. No error reported.
    

    We’ll add grub.cfg file under /mnt/usb/boot/grub/ directory. It defines selectable menus and the booting method of each entry. This time I’ll add Ubuntu Desktop ISO for i386 platform.

    set timeout=5
    set default=0
    
    menuentry "Ubuntu Desktop 16.04.3 LTS i386" {
      set isofile="/iso/ubuntu-16.04.3-desktop-i386.iso"
      loopback loop $isofile
      linux (loop)/casper/vmlinuz boot=casper file=/preseed/ubuntu.seed iso-scan/filename=$isofile noeject noprompt splash --
      initrd (loop)/casper/initrd.lz
    }
    
    menuentry "Ubuntu Desktop 16.04.3 LTS amd64" {
      set isofile="/iso/ubuntu-16.04.3-desktop-amd64.iso"
      loopback loop $isofile
      linux (loop)/casper/vmlinuz.efi boot=casper file=/preseed/ubuntu.seed iso-scan/filename=$isofile noeject noprompt splash --
      initrd (loop)/casper/initrd.lz
    }
    
    menuentry "Ubuntu Server 16.04.3 LTS i386" {
      set isofile="/iso/ubuntu-16.04.3-server-i386.iso"
      loopback loop $isofile
      linux (loop)/install/vmlinuz boot=casper file=/preseed/ubuntu-server.seed iso-scan/filename=$isofile noeject noprompt splash --
      initrd (loop)/install/initrd.gz
    }
    
    menuentry "Ubuntu Server 16.04.3 LTS amd64" {
      set isofile="/iso/ubuntu-16.04.3-server-amd64.iso"
      loopback loop $isofile
      linux (loop)/install/vmlinuz boot=casper file=/preseed/ubuntu-server.seed iso-scan/filename=$isofile noeject noprompt splash --
      initrd (loop)/install/initrd.gz
    }
    
    menuentry "Linux Mint 18.2 Cinnamon 32-bit" {
      set isofile="/iso/linuxmint-18.2-cinnamon-32bit.iso"
      loopback loop $isofile
      linux (loop)/casper/vmlinuz boot=casper file=/preseed/linuxmint.seed iso-scan/filename=$isofile noeject noprompt splash --
      initrd (loop)/casper/initrd.lz
    }
    
    menuentry "Custom ELF" {
      elffile="/elf/custom.elf"
      multiboot $elffile
    }
    

    In the first menuentry, isofile points to /iso/ubuntu-16.04.3-desktop-i386.iso, and it’s relative path of the USB stick. Create /mnt/usb/iso/ directory, and put the ISO files under there.

    You may need to look inside of ISO file to find where is vmlinuz* and initrd.* files. Try this:

    isoinfo -l -i myimage.iso
    

    As the similar way, you can also make it to boot from ELF file. Just put the ELF file that supports Multiboot under /mnt/usb/elf/ directory, and edit the menuentry properly.

    After editing is done, unmount the disk and use it right away!

    sudo umount /dev/sdb1
    

    Troubleshooting

    If your screen goes black on boot, try with nomodeset:

    linux ... noeject noprompt splash nomodeset --
    

    See also

  • Pushing git repository to multiple remotes

    I’m currently managing my dotfiles repository on both of GitHub and Bitbucket. These two repositories are the same, but I don’t want to remove one of them. I mainly use GitHub for hosting code now, but the first place I uploaded my dotfiles to was Bitbucket.

    I want to keep the HEAD of two remote repositories be the same, so when I push code to my dotfiles, the both of them must be updated at the same time.

    Default git config

    First, clone or init the repository.

    git clone https://github.com/yous/dotfiles.git
    

    Then, as you know, the origin will be set to https://github.com/yous/dotfiles.git. This is the content of .git/config:

    [core]
    	# ...
    [remote "origin"]
    	url = https://github.com/yous/dotfiles.git
    	fetch = +refs/heads/*:refs/remotes/origin/*
    [branch "master"]
    	# ...
    

    Note that there is the url attribute under remote "origin".

    git remote set-url

    Now we’re going to run git remote set-url twice so that the repository will have two push remote URLs. Setting push remote URL is slightly different from plaing git remote set-url <name> <newurl>. See man git-remote:

    set-url
        Changes URLs for the remote. Sets first URL for remote <name> that
        matches regex <oldurl> (first URL if no <oldurl> is given) to
        <newurl>. If <oldurl> doesn't match any URL, an error occurs and
        nothing is changed.
    
        With --push, push URLs are manipulated instead of fetch URLs.
    
        With --add, instead of changing existing URLs, new URL is added.
    

    So we need to run git remote set-url --push <name> <newurl>. Moreover, we need two push URL, so the second command should be git remote set-url --add --push <name> <newurl>. It’s okay to specify --add --push to the first command, too.

    git remote set-url --add --push origin https://github.com/yous/dotfiles.git
    git remote set-url --add --push origin https://bitbucket.org/yous/dotfiles.git
    

    Now, the content of .git/config would be like this:

    [core]
    	# ...
    [remote "origin"]
    	url = https://github.com/yous/dotfiles.git
    	fetch = +refs/heads/*:refs/remotes/origin/*
    	pushurl = https://github.com/yous/dotfiles.git
    	pushurl = https://bitbucket.org/yous/dotfiles.git
    [branch "master"]
    	# ...
    

    All done! Note that there are two pushurls under remote "origin". Now git push automatically pushes to the both push remote URLs.

  • Boston Key Party CTF 2017: vimjail write-up

    vimjail (pwn 150)

    Can you read the flag?

    UPDATES

    • (13:38 UTC Saturday): The flag is not in /tmp.
    • (13:31 EST Saturday): new ip

    Looking around

    Well, you would do ls first when you logged in, so do we. And there was ~/flagReader.

    [email protected]:~$ ls -als /home/ctfuser/flagReader
    12 ---S--x--- 1 topsecretuser secretuser 8768 Feb 25 08:42 /home/ctfuser/flagReader
    

    If you try completion by pressing Tab key or try to move around using cd, it fails with an error message from rbash. It’s restricted bash, but you can simply run bash to escape.

    While moving around, we found nothing special without /.flag. Also there were some .s[a-z][a-z] files under /var/tmp/ and /tmp/, created by secretuser. But there are not in fixed location when the problem server was changed, so we thought there would be a way to run Vim under secretuser’s permission.

    [email protected]:~$ ls -als /.flag
    4 -r-------- 1 topsecretuser topsecretuser 39 Feb 25 08:42 /.flag
    

    We also tried to find setuid or setgid files, but there was only the previous flagReader.

    [email protected]:/tmp$ find / -perm -4000 -o -perm -2000 -type f 2>/dev/null
    /bin/ping
    /bin/ping6
    /bin/fusermount
    /bin/umount
    /bin/su
    /bin/mount
    /bin/ntfs-3g
    /sbin/unix_chkpwd
    /sbin/pam_extrausers_chkpwd
    /usr/lib/x86_64-linux-gnu/utempter/utempter
    /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
    /usr/lib/openssh/ssh-keysign
    /usr/lib/snapd/snap-confine
    /usr/lib/eject/dmcrypt-get-device
    /usr/lib/dbus-1.0/dbus-daemon-launch-helper
    /usr/lib/policykit-1/polkit-agent-helper-1
    /usr/bin/crontab
    /usr/bin/newuidmap
    /usr/bin/at
    /usr/bin/chage
    /usr/bin/sudo
    /usr/bin/bsd-write
    /usr/bin/pkexec
    /usr/bin/chfn
    /usr/bin/expiry
    /usr/bin/newgrp
    /usr/bin/screen
    /usr/bin/chsh
    /usr/bin/gpasswd
    /usr/bin/newgidmap
    /usr/bin/ssh-agent
    /usr/bin/passwd
    /usr/bin/mlocate
    /home/ctfuser/flagReader
    

    Read on →

  • 33C3 CTF 2016: pdfmaker write-up

    pdfmaker (misc 75)

    Just a tiny application, that lets the user write some files and compile them with pdflatex. What can possibly go wrong?

    nc 78.46.224.91 24242

    If you can’t download the application, please use this link.

    What is the goal?

    There are some interesting parts in pdfmaker_public.py. initConnection copies flag file into the self.directory with the name of:

    "33C3" + "%X" % randint(0, 2**31) + "%X" % randint(0, 2**31)
    

    Since the answer would be in the 33C3XXXXXXXXXXXXXXXX file, we should get the list of filenames in its directory. Note that create method can create log, tex, sty, mp, bib files.

    Behavior of \write18

    @daehee found this helpful link: “Pwning coworkers thanks to LaTeX”. According to the post, \write18 normally executes any program listed in shell_escape_commands:

    shell_escape_commands = \
    bibtex,bibtex8,\
    extractbb,\
    kpsewhich,\
    makeindex,\
    mpost,\
    repstopdf,\
    

    Note that mpost is in there, and we can create mp file! As denoted by the link, mpost takes the -tex option for text labels, so we can execute arbitrary program.

    Read on →

  • HITCON CTF 2016: ROP write-up

    ROP (Reverse 250)

    Description

    Who doesn’t like ROP?
    Let’s try some new features introduced in 2.3.

    rop.iseq

    Hint

    None

    If the above link doesn’t work, please use this link.

    New features?

    Well, see the Ruby 2.3.0 news.

    RubyVM::InstructionSequence#to_binary and .load_from_binary are introduced as experimental features. With these features, we can make a ISeq (bytecode) pre-compilation system.

    Yes, so this is about using RubyVM::InstructionSequence.load_from_binary. Let’s just start with:

    RubyVM::InstructionSequence.load_from_binary(File.read('rop.iseq'))
    

    But you can face this kind of error:

    RuntimeError: unmatched platform
            from (irb):1:in `load_from_binary'
            from (irb):1
            from /usr/bin/irb:11:in `<main>'
    

    By checking strings rop.iseq, we can find x86_64-linux. So we need Ruby 2.3 on Linux x86_64 platform. You can see the platform by ruby --version. This is the version of my one:

    ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
    

    Read on →