Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

Have you ever run Robocopy on Linux?

Cross-platform is a term we're used to hear several times per day. It means a component can run on different platforms without any significant modifications. In the context of software, it means the same piece of software can be run on…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Cross-platform is a term we're used to hear several times per day. It means a component can run on different platforms without any significant modifications. In the context of software, it means the same piece of software can be run on different operating systems without worrying about the underlying platform that runs it.




Of course, there are some situations where this doesn't apply, but let's assume this scenario doesn't exist.




We can summarize the cross-platform concept with the motto: "Build once, run everywhere".



If this motto rang a bell in your head, you're in the right place, and you should go ahead with the reading. In fact, this is one of the fundamental pillars of Docker.



Today, I'll show how I put in practice this concept in the last pet project I did.






Windows Robocopy... On Linux




Disclaimer: I wasn't able to run Windows Robocopy on my machine running Ubuntu 24.04 LTS. Robocopy is a Windows-based tool. In Linux, there are alternatives like cp or rsync, among others. Being able to run Robocopy on Linux is beyond cross-platform; it's more like magic.




The idea behind this project has been to develop, build, run, and test a Windows-native application on an incompatible machine, which was Linux-based.



The final application will be consumed directly in your terminal, exposing a Command-Line-Interface (in short CLI) API.






The Journey



In a nutshell, the journey of this application has consisted of:




  1. Development of the core feature

  2. Set up the CI/CD process to build and release the application

  3. Manual run of the binary on a Windows machine for testing purposes

  4. Automatic testing of the application on a Windows machine



The most appealing part turned out to be the automatic testing of the application (point 4).



In today's adventure, my travel companions will be #Go, #Docker, and the #dockerSDK. In case you're not familiar with the DockerSDK, it's a smart way to programmatically interact with the Docker Daemon from your Go code. Thanks to this pet project, I managed to familiarize myself with it.




Disclaimer: if you're eager to see the code, you can check it out in my GitHub profile.




Now, let's unveil ten uh-oh moments I came across.






1. dockur/windows image



The dockur/windows image discovery has been mindblowing. While surfing the Internet, I randomly came across this Docker image that allows you to run Windows... in a container!



Visit the Dockur GitHub page for more details. Over there, you can also find a super nice introductory video to quickly ramp up.




If you're curious about how this image works under the hood, refer to their documentation, where you should find every technical detail.




In the documentation, there's a handy docker-compose.yml ready to use. It resembles something like this:




services:
windows:
image: dockurr/windows
container_name: windows
environment:
VERSION: "11l"
KEYBOARD: "it-IT"
REGION: "en-US"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 8006:8006
- 5985:5985
- 3389:3389/tcp
- 3389:3389/udp
volumes:
- ./windows:/storage
- ./testdata:/shared
restart: always
stop_grace_period: 2m






This is an extremely powerful tool, but it comes with considerations.






First Run



If you're familiar with Windows-based operating systems, you'd also be familiar with their setup process... The first time you run this image, you are walked through the initialization process where you can customize settings.



The last thing you want is to have to go, yet another time, through this lengthy process. To bypass this, you can use a Docker volume:




    volumes:
- ./windows:/storage






For convenience, I used the windows folder, located in the root of my project.



TL;DR: Embrace a bit of patience and run this container.






Purposes



This Windows container is used for two purposes:




  • performing manual testing

  • performing automatic testing



The first consists of manually connecting to the Windows Desktop instance (you can easily do that in your browser), performing the action, and checking the results. The latter is done in the end-to-end test that leverages the capabilities of a tool called Windows Remote Management (WinRM).



Having this properly set up was mandatory for the successful project.






Automated Testing Process



The diagram below depicts the automated testing process our application should undergo to be considered healthy:




automated testing workflow diagram



The process is straightforward:




  1. Building the Docker image starting from the source code

  2. Creation of a container with the final executable binary (called extractor)

  3. Copying out the binary from the extractor container

  4. Copying the binary to the running Windows container

  5. Testing the binary on the Windows container



Now, let's start exploring the capabilities offered by the Docker SDK.






2. The Docker Client



The Docker SDK wraps the HTTP calls done against the Docker Daemon. These are the same calls done when interacting with Docker via the Docker CLI or the Docker Desktop environment. To consume these APIs, a Docker Client must be created in our code. That's where the client.Client struct shines.



The client.Client exposed by the Docker Module provides you with a handle to interact.



We initialized the Docker client in the robocopy_test.go file:




func setupDockerClient(ctx context.Context) (err error) {
dockerClient, err = client.NewClientWithOpts(client.FromEnv)
if err != nil {
return err
}
dockerClient.NegotiateAPIVersion(ctx)
return nil
}






Please note dockerClient.NegotiateAPIVersion(ctx) is needed to match the version used by the API.




All the subsequent code snippets are taken from the robocopy_test.go file.







3. List Containers



Listing the containers on your host can be done via the ContainerList method, as you can see below:




func getWindowsContainerID(ctx context.Context, dockerClient *client.Client) (*string, error) {
containers, err := dockerClient.ContainerList(ctx, container.ListOptions{})
if err != nil {
return nil, err
}
for _, c := range containers {
if c.Image == windowsImageName {
return &c.ID, nil
}
}
return nil, fmt.Errorf("no running Windows container found")
}









4. Building a Docker image



One of the most interesting parts. The code looks like this:




func buildDockerImageForRobocopyBinary(ctx context.Context) error {
// create tarball from source code
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
defer tw.Close()
if err := createTarball(".", tw); err != nil {
return err
}
twReader := bytes.NewReader(buf.Bytes())
imageBuildRes, err := dockerClient.ImageBuild(ctx, twReader, build.ImageBuildOptions{
Tags: []string{"test-my-robocopy"},
Remove: true,
})
if err != nil {
return err
}
defer imageBuildRes.Body.Close()
if _, err := io.Copy(os.Stdout, imageBuildRes.Body); err != nil {
return err
}
return nil
}






The process consists of two steps:




  • creation of a tar archive with the application's source code

  • running the ImageBuild method by passing:


    • a tar reader

    • the image build options








The unspecified options resolve with the default values. Please be sure to have the Dockerfile placed in the root of the project




I encourage you to dig into the createTarball function to learn more about the creation of the tar archive.







5, 6, 7 Containers Management



Here, there are three things tied together. Let me share the code, and then I'll walk you through:




func copyBinaryToWindowsContainer(ctx context.Context) error {
// creation of the extractor container
containerRes, err := dockerClient.ContainerCreate(ctx, &container.Config{
Image: "test-my-robocopy",
Cmd: []string{"echo", "hello"},
}, nil, nil, nil, "extractor")
if err != nil {
return err
}
extractorContainerID = containerRes.ID
// pull out the binary from the extractor container
reader, _, err := dockerClient.CopyFromContainer(ctx, containerRes.ID, "/go-robocopy.exe")
if err != nil {
return err
}
defer reader.Close()
// copy binary to the target Windows Container
return dockerClient.CopyToContainer(ctx, *windowsContainerID, "./shared", reader, container.CopyToContainerOptions{})
}






The process is:




  • creating the extractor container based on the test-my-robocopy image we tagged before

  • copying from the extractor container the binary produced (/go-robocopy.exe)

  • copying to the windows container the executable binary






8, 9 Images Management



Now, we're entering the cleanup process. The goal is to get rid of the image built for the test. First, the code:




func removeDockerImagesByRepoTags(ctx context.Context, repo, tag string) error {
filters := filters.NewArgs(filters.Arg("label", fmt.Sprintf("repo=%v", repo)), filters.Arg("label", fmt.Sprintf("tag=%v", tag)))
images, err := dockerClient.ImageList(ctx, image.ListOptions{Filters: filters})
if err != nil {
return err
}
for _, img := range images {
if _, err := dockerClient.ImageRemove(ctx, img.ID, image.RemoveOptions{}); err != nil {
return err
}
}
return nil
}






The process is:




  • building the filter since we want to filter images on two criteria:



    • repo where we passed in the value test-my-robocopy


    • tag where we passed in the value latest since we did not specify any tag for the image (bad practice: always specify tags)






  • retrieval of matching Docker images


  • Docker images removal







10. Container Removal



Last, we remove the extractor container with this trivial cleanup function:




func removeContainerByID(ctx context.Context, containerID string) error {
return dockerClient.ContainerRemove(ctx, containerID, container.RemoveOptions{})
}









Untold Stories



If you navigate the GitHub Repository, you'll notice a lot of stuff that has not been covered. These can be topics for future posts. An extract of the list can be:




  • Git Hooks

  • GitHub Actions

  • Goreleaser


  • tar archive in Go

  • Windows Remote Management (WinRM)

  • working with CLI-apps and flags in Go



If you want me to cover any of these topics, feel free to reach out.






Outro



I had a lot of fun with this project. Especially, I could have adopted any unneeded complexity without having to worry about the old-good patterns, best practices, and guidelines. After all, this is the beauty of useless pet projects.



Thanks for your attention, folks! If you have any questions, doubts, feedback, or comments, I'm available to listen and discuss. If you want me to cover some specific concepts, please reach out.

1. Sofort-Triage & Abwehrmaßnahmen

SOC Incident Playbook: Remote Code Execution (RCE) Defense
Syntax validiert (0 Fehler)
title: Detect Exploitation - Have you ever run Robocopy on Linux?
id: 73742307-f357-4cfa-b02d-4f7c8e04a0ab
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-25
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-25"
        description = "YARA Signature for "
    strings:
        $str = "Have you ever run Robocopy on " ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("Have you ever run Robocopy on Linux")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*Have you ever run Robocopy on Linux*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "Have you ever run Robocopy on Linux"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc

2. Cyber Threat Intelligence & Forensik

CTI Threat Relationship Graph2 Knoten / 1 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich Have you ever run Robocopy on Linux?.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Have you ever run Robocopy on Linux?

Thematisch verwandte Begriffe: Have, ever, Robocopy, Linux · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-97818 | phpIPAM through 1.8.3 has incorrect authorization for id=="admins" and i…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag