So there has been a lot of talk with Twitter SMS spoofing in the news recently, celebrity accounts were ‘hacked’ simply by sending an SMS. Sending an SMS, a hack? Not in my books. So got me thinking, what do Twitter use at the core of the system?

For those with a keen eye you will see Cloudhopper, but what’s that?

Turns out it’s ch_smpp, stands for Cloudhopper SMPP, an open source SMPP client/server framework.fizzed/cloudhopper-smpp
Efficient, scalable, and flexible Java implementation of the Short Messaging Peer to Peer Protocol (SMPP) …github.com

So, now we must ask, would it not be better to try and own the core system instead of just spoofing messages?

Of course that answer is always yes.

So, we start by deploying an instance of Cloudhopper on in the lab…

This post is focused on making a quick, simple fuzzer so I won’t go in to vulnerability research here, we will skip a few steps and just get in to fuzzing user controlled inputs.

For this simple fuzzer we will use python-smpplibpython-smpplib/python-smpplib
SMPP library for Python. Contribute to python-smpplib/python-smpplib development by creating an account on GitHub.github.com

We can start with the example code, it’s a good boilerplate

import logging
import sys
import smpplib.gsm
import smpplib.client
import smpplib.consts
# if you want to know what's happening
logging.basicConfig(level='DEBUG')
# Two parts, UCS2, SMS with UDH
parts, encoding_flag, msg_type_flag = smpplib.gsm.make_parts(u'Привет мир!\n'*10)
client = smpplib.client.Client('example.com', SOMEPORTNUMBER)
# Print when obtain message_id
client.set_message_sent_handler(
lambda pdu: sys.stdout.write('sent {} {}\n'.format(pdu.sequence, pdu.message_id)))
client.set_message_received_handler(
lambda pdu: sys.stdout.write('delivered {}\n'.format(pdu.receipted_message_id)))
client.connect()
client.bind_transceiver(system_id='login', password='secret')
for part in parts:
pdu = client.send_message(
source_addr_ton=smpplib.consts.SMPP_TON_INTL,
#source_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
# Make sure it is a byte string, not unicode:
source_addr='SENDERPHONENUM',
        dest_addr_ton=smpplib.consts.SMPP_TON_INTL,
#dest_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
# Make sure thease two params are byte strings, not unicode:
destination_addr='PHONENUMBER',
short_message=part,
        data_coding=encoding_flag,
esm_class=msg_type_flag,
registered_delivery=True,
)
print(pdu.sequence)
client.listen()

We need to add our lab ip and port number, in this case it’s local and also add the default cloudhopper creds…

client = smpplib.client.Client('0.0.0.0', 2776)
client.bind_transceiver(system_id='smppclient1', password='password')

This is going to be a very simple, dumb fuzzer like the one you learn for FTP when you take OSCP.

So all we really want to do, is loop through a pre-defined number range and then send the longer payloads each loop to the SMPP Cloudhopper server.

Client — sending requests, fuzzing message field
server receiving requests

In this case, the messages are chunked so it’s not particularly useful or likely that we can overflow anything like this but this code means we can go on to testing the to and from fields. After this, you can start testing for known payloads for Java and other fuzzing lists that may uncover unexpected application behaviour or faults.

A little caveat, Java is a little different in my experience to exploit than what most people are used to, injection etc all have little quirks, we will save Java exploitation for another day as it is worth a post of it’s own.

Let’s assume we just want to see the world burn and crash the program, we could try and write x*y payload to any of the user controlled inputs.

In this example code we loop through a number range of 1 to 4000, then we take A and multiply it by the current loop value. So first payload will be “A”, A*1.

import logging
import sys
import smpplib.gsm
import smpplib.client
import smpplib.consts
# if you want to know what's happening
logging.basicConfig(level='DEBUG')
for i in range(1, 4000):
# Two parts, UCS2, SMS with UDH
payload = "A"*i
parts, encoding_flag, msg_type_flag = smpplib.gsm.make_parts(payload)
client = smpplib.client.Client('0.0.0.0', 2776)
# Print when obtain message_id
client.set_message_sent_handler(
lambda pdu: sys.stdout.write('sent {} {}\n'.format(pdu.sequence, pdu.message_id)))
client.set_message_received_handler(
lambda pdu: sys.stdout.write('delivered {}\n'.format(pdu.receipted_message_id)))
client.connect()
client.bind_transceiver(system_id=payload, password=payload)
for part in parts:
pdu = client.send_message(
source_addr_ton=smpplib.consts.SMPP_TON_INTL,
#source_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
# Make sure it is a byte string, not unicode:
source_addr=payload,
dest_addr_ton=smpplib.consts.SMPP_TON_INTL,
#dest_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
# Make sure thease two params are byte strings, not unicode:
destination_addr=payload,
short_message=part,
data_coding=encoding_flag,
esm_class=msg_type_flag,
registered_delivery=True,
)
print(pdu.sequence)
client.listen()

I have marked all the areas you could try changing values for or adding a static value such as destination number and then fuzz the rest. Or you may want to isolate just one.

In this case a quick run of the dumb fuzzer came up with nothing, but remember this…

Can’t remember where I saw this, but you get the point of why this kind of crude testing can be worth it.

I will update this post with any progress on researching Cloudhopper vulnerabilities and any further updates to smpp fuzzing script. Happy pwning.