Egress from ISPs and Proxy Services Reported in DPRK Worker Cases

Identity / cloudNetwork

IOC Hunt medium DPRK IT Worker FraudLaptop Farm

The addresses operators appear on when the VPN is not in the way: Russian TTK ranges around Khabarovsk, China Unicom, and the commercial proxy and hosting services named in recent casework.

What this hunt looks for

ReliaQuest's central observation is that operators slip: the same account authenticates through Astrill one day and from the Russian ISP TransTelekom the next. ReliaQuest publishes the TTK addresses seen in these campaigns, many in Khabarovsk, and China Unicom addresses found investigating North Korean incidents; Mandiant's table carries three of the same China Unicom addresses.

Huntress advises monitoring authentication through IPRoyal Proxy and infrastructure associated with WorkTitans B.V. in its 2026 casework. Where an employee's account has ever authenticated from any of these, that is a lead that does not depend on VPN attribution at all.

Technique
Session origin inconsistent with claimed residence, surfaced through proxy and hosting infrastructure (MITRE ATT&CK T1090, T1090.003) associated with fraudulently obtained employment (T1078).
Data sources
Identity provider sign-in logs, VPN/firewall logs, Proxy logs
Last updated
2026-10-04

Indicators

The atomic values this hunt matches on, listed separately from the queries so they can be lifted into tooling that speaks none of the query languages below. Every value here is reported by one of the sources cited at the foot of this page.

TypeValueNote
IP 80.237.84.12 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 80.237.87.21 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 83.234.227.33 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 83.234.227.34 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 83.234.227.35 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 83.234.227.36 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 83.234.227.37 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 83.234.227.38 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 188.43.33.252 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 188.43.136.41 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 188.43.136.115 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 188.43.253.77 TransTelekom (TTK), Russia; many geolocated in Khabarovsk. Published by ReliaQuest as associated with this campaign.
IP 42.84.228.232 China Unicom, found by ReliaQuest while investigating North Korean incidents; 42.84.228.232, 60.20.1.234 and 113.227.237.46 also appear in Mandiant's table.
IP 60.20.1.234 China Unicom, found by ReliaQuest while investigating North Korean incidents; 42.84.228.232, 60.20.1.234 and 113.227.237.46 also appear in Mandiant's table.
IP 139.215.45.250 China Unicom, found by ReliaQuest while investigating North Korean incidents; 42.84.228.232, 60.20.1.234 and 113.227.237.46 also appear in Mandiant's table.
IP 113.227.237.46 China Unicom, found by ReliaQuest while investigating North Korean incidents; 42.84.228.232, 60.20.1.234 and 113.227.237.46 also appear in Mandiant's table.
IP 123.190.56.214 China Unicom, found by ReliaQuest while investigating North Korean incidents; 42.84.228.232, 60.20.1.234 and 113.227.237.46 also appear in Mandiant's table.
Service IPRoyal Proxy Commercial proxy provider Huntress advises monitoring authentication through (2026-08-26).
Service WorkTitans B.V. Hosting provider whose infrastructure Huntress advises monitoring (2026-08-26).
Certificate subject hangro.net.kp North Korean ccTLD subject name found by ReliaQuest in a certificate tied to a Russian address.

Logic

Every query below implements these steps, so the same hunt returns the same result in each product.

  1. Collect: Entra ID and Okta sign-ins; DNS and connection records from endpoints and proxies
  2. Match: sign-in source address is one of the 17 TTK or China Unicom addresses published by ReliaQuest and Mandiant
  3. Match: or a looked-up or contacted name contains iproyal, worktitans or hangro.net.kp (optionally any .kp name)
  4. Report: users and devices with the matched address or name, newest first

Queries

Defender / Sentinel KQL

Written for this site, from indicators reported by ReliaQuest, Mandiant, Huntress

Rows are users (sign-ins) or devices (lookups) that touched a reported address or name; these are ISP and proxy ranges with ordinary customers, so treat a hit as a lead.

// Hunt: egress from ISPs and proxy services reported in DPRK worker cases. ReliaQuest publishes 83.234.227.33-8 in compressed form; .33 to .38 is the reading used.
let ReportedAddresses = dynamic(["80.237.84.12", "80.237.87.21", "83.234.227.33", "83.234.227.34", "83.234.227.35", "83.234.227.36", "83.234.227.37", "83.234.227.38", "188.43.33.252", "188.43.136.41", "188.43.136.115", "188.43.253.77", "42.84.228.232", "60.20.1.234", "139.215.45.250", "113.227.237.46", "123.190.56.214"]);
union
( union SigninLogs, AADNonInteractiveUserSignInLogs
  | where TimeGenerated > ago(90d)
  | where IPAddress in (ReportedAddresses)
  | project Timestamp = TimeGenerated, Subject = UserPrincipalName, Signal = "reported-signin-address", Evidence = strcat(IPAddress, " ", AppDisplayName) ),
( DeviceNetworkEvents
  | where Timestamp > ago(90d)
  | where RemoteUrl has_any ("iproyal", "worktitans") or RemoteUrl contains "hangro.net.kp"
      // optional: any North Korean (.kp) name, not only the certificate subject ReliaQuest found
      or RemoteUrl endswith ".kp"
  | project Timestamp, Subject = DeviceName, Signal = "proxy-or-kp-name", Evidence = RemoteUrl )
| summarize Events = count(), Signals = make_set(Signal), Evidence = make_set(Evidence, 10), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by Subject
| sort by LastSeen desc
Lower-fidelity parts (1)
  • the .kp suffix test — it widens the sourced certificate subject to every .kp name. Remove: delete the // optional: any North Korean line and the or RemoteUrl endswith line under it

Splunk SPL

Written for this site, from indicators reported by ReliaQuest, Mandiant, Huntress

Sign-in addresses and name lookups across identity, DNS and proxy data per user or source address.

```Placeholders: index=identity holds Okta, Entra ID or ms:aad:signin events with src_ip and user extracted; index=dns or index=proxy hold name lookups and web requests.```
(index=identity (sourcetype=okta OR sourcetype=azuread OR sourcetype="ms:aad:signin") src_ip IN ("80.237.84.12", "80.237.87.21", "83.234.227.33", "83.234.227.34", "83.234.227.35", "83.234.227.36", "83.234.227.37", "83.234.227.38", "188.43.33.252", "188.43.136.41", "188.43.136.115", "188.43.253.77", "42.84.228.232", "60.20.1.234", "139.215.45.250", "113.227.237.46", "123.190.56.214"))
    OR ((index=dns OR index=proxy) ("iproyal" OR "worktitans" OR "hangro.net.kp"
        ```optional: any North Korean (.kp) name``` OR "*.kp"))
| eval signal=if(index="identity", "reported-signin-address", "proxy-or-kp-name"), subject=coalesce(user, src_ip)
| stats count AS events values(signal) AS signals values(src_ip) AS addresses min(_time) AS first_seen max(_time) AS last_seen BY subject
| convert ctime(first_seen) ctime(last_seen)
| sort - last_seen
Lower-fidelity parts (1)
  • the *.kp term — it widens the sourced certificate subject to every .kp name. Remove: delete the ```optional comment and the OR "*.kp" term after it

CrowdStrike LogScale

Written for this site, from indicators reported by ReliaQuest, Mandiant, Huntress

Free-text address match over ingested sign-in events plus DnsRequest name matches from Falcon.

// Hunt: egress from ISPs and proxy services reported in DPRK worker cases. Scope the query to the repository holding your sign-in events; the address is matched as a whole token, so no parser field name is assumed.
regex("(?:^|[^0-9.])(?<matchedIp>80[.]237[.]84[.]12|80[.]237[.]87[.]21|83[.]234[.]227[.]33|83[.]234[.]227[.]34|83[.]234[.]227[.]35|83[.]234[.]227[.]36|83[.]234[.]227[.]37|83[.]234[.]227[.]38|188[.]43[.]33[.]252|188[.]43[.]136[.]41|188[.]43[.]136[.]115|188[.]43[.]253[.]77|42[.]84[.]228[.]232|60[.]20[.]1[.]234|139[.]215[.]45[.]250|113[.]227[.]237[.]46|123[.]190[.]56[.]214)(?:[^0-9.]|$)", strict=false)
| regex("(?:userPrincipalName|alternateId)[^a-zA-Z0-9_]+(?<user>[^\"]+)", strict=false)
| case {
    #event_simpleName=DnsRequest DomainName=/iproyal|worktitans|hangro[.]net[.]kp/i | signal := "proxy-or-kp-name";
    // optional: any North Korean (.kp) name
    #event_simpleName=DnsRequest DomainName=/[.]kp$/i | signal := "proxy-or-kp-name";
    matchedIp=* | signal := "reported-signin-address";
    * | signal := "";
  }
| signal != ""
| groupBy([signal, matchedIp, user, ComputerName], function=[count(as=events), min(@timestamp, as=firstSeen), max(@timestamp, as=lastSeen)])
| sort(lastSeen, order=desc)
Lower-fidelity parts (1)
  • the .kp suffix branch — it widens the sourced certificate subject to every .kp name. Remove: delete the // optional comment and the DomainName=/[.]kp$/i line under it

Elastic

Written for this site, from indicators reported by ReliaQuest, Mandiant, Huntress

Sign-ins from the reported addresses and DNS lookups of the named services, per subject.

FROM logs-azure.signinlogs-*, logs-okta*, logs-endpoint.events.network-*
| WHERE @timestamp > NOW() - 90 days
| EVAL src = TO_STRING(source.ip)
| EVAL name = TO_LOWER(COALESCE(dns.question.name, ""))
| EVAL signal = CASE(
    src IN ("80.237.84.12", "80.237.87.21", "83.234.227.33", "83.234.227.34", "83.234.227.35", "83.234.227.36", "83.234.227.37", "83.234.227.38", "188.43.33.252", "188.43.136.41", "188.43.136.115", "188.43.253.77", "42.84.228.232", "60.20.1.234", "139.215.45.250", "113.227.237.46", "123.190.56.214"), "reported-signin-address",
    name RLIKE ".*(iproyal|worktitans|hangro[.]net[.]kp).*", "proxy-or-kp-name",
    "")
| EVAL signal = CASE(signal != "", signal, name RLIKE ".*[.]kp", "proxy-or-kp-name", "")
| WHERE signal != ""
| EVAL subject = COALESCE(azure.signinlogs.properties.user_principal_name, user.name, host.name)
| STATS events = COUNT(*), signals = VALUES(signal), first_seen = MIN(@timestamp), last_seen = MAX(@timestamp) BY subject
| SORT last_seen DESC
Lower-fidelity parts (1)
  • the .kp EVAL line — it widens the sourced certificate subject to every .kp name. Remove: delete the second `| EVAL signal = CASE(signal != ""` line

Cortex XQL

Written for this site, from indicators reported by ReliaQuest, Huntress

Endpoint lookups of the named proxy services and .kp names per host.

// Hunt: proxy-service and .kp names from endpoints. Sign-in addresses need your identity data, which xdr_data does not hold.
dataset = xdr_data
| filter event_type = ENUM.NETWORK and (dns_query_name ~= "(?i)iproyal|worktitans|hangro[.]net[.]kp"
        or action_external_hostname ~= "(?i)iproyal|worktitans|hangro[.]net[.]kp"
        // optional: any North Korean (.kp) name
        or dns_query_name ~= "(?i)[.]kp$")
| comp count() as events, values(dns_query_name) as names, min(_time) as first_seen, max(_time) as last_seen by agent_hostname
| sort desc last_seen
Lower-fidelity parts (1)
  • the .kp suffix test — it widens the sourced certificate subject to every .kp name. Remove: delete the // optional comment and the dns_query_name ~= line under it

False positives and tuning

These addresses are ISP and hosting infrastructure with ordinary customers and date from the reports that published them, so treat them as historical examples, not live indicators.

ReliaQuest publishes 83.234.227.33-8 in compressed form, expanded here as .33 through .38; verify that reading against the source before acting on the middle of the range.

IPRoyal and comparable proxy services carry much legitimate traffic, so a name hit is a lead; a sign-in from a reported address is a reason to look, not a finding.

Sources

Tuning required before use This hunt is a starting point. Adapt the queries to your schema, validate them against your baseline and tune them for the false positives noted above. Indicators go stale as operators rotate hosts.