The USB GSM modem, MF190, comes with properties like appearing as a CD-ROM drive on Linux or as a mass storage device or both. In our case, on Kali Linux, this device appeared as 3 different devices: a CD-ROM device /dev/sr1
, a mass storage device /dev/sdc
and a USB modem /dev/ttyUSB2
. These device names can be extracted from the dmesg
output as below as soon as you plugin the USB device to your computer.
$ sudo dmesg | tail -n 1000
[1800781.986806] usb 1-2.4.2: new high-speed USB device number 7 using ehci-pci
[1800782.197336] usb 1-2.4.2: New USB device found, idVendor=19d2, idProduct=2000, bcdDevice= 0.00
[1800782.197343] usb 1-2.4.2: New USB device strings: Mfr=3, Product=2, SerialNumber=4
[1800782.197347] usb 1-2.4.2: Product: ZTE WCDMA Technologies MSM
[1800782.197350] usb 1-2.4.2: Manufacturer: ZTE,Incorporated
[1800782.197352] usb 1-2.4.2: SerialNumber: MF1900ZTED010000
[1800782.199979] usb-storage 1-2.4.2:1.0: USB Mass Storage device detected
[1800782.201943] scsi host3: usb-storage 1-2.4.2:1.0
[1800783.221344] scsi 3:0:0:0: CD-ROM ZTE USB SCSI CD-ROM 2.31 PQ: 0 ANSI: 2
[1800783.225970] sr 3:0:0:0: [sr1] scsi-1 drive
[1800783.243508] sr 3:0:0:0: Attached scsi CD-ROM sr1
[1800783.243741] sr 3:0:0:0: Attached scsi generic sg4 type 5
[1800784.752096] usb 1-2.4.2: USB disconnect, device number 7
[1800785.078898] usb 1-2.4.2: new high-speed USB device number 8 using ehci-pci
[1800785.290082] usb 1-2.4.2: New USB device found, idVendor=19d2, idProduct=0117, bcdDevice= 0.00
[1800785.290090] usb 1-2.4.2: New USB device strings: Mfr=3, Product=2, SerialNumber=4
[1800785.290093] usb 1-2.4.2: Product: ZTE WCDMA Technologies MSM
[1800785.290096] usb 1-2.4.2: Manufacturer: ZTE,Incorporated
[1800785.290099] usb 1-2.4.2: SerialNumber: MF1900ZTED010000
[1800785.293883] usb-storage 1-2.4.2:1.3: USB Mass Storage device detected
[1800785.294205] scsi host3: usb-storage 1-2.4.2:1.3
[1800785.974549] usbcore: registered new interface driver option
[1800785.976340] usbserial: USB Serial support registered for GSM modem (1-port)
[1800785.977650] option 1-2.4.2:1.0: GSM modem (1-port) converter detected
[1800785.977975] usb 1-2.4.2: GSM modem (1-port) converter now attached to ttyUSB0
[1800785.978392] option 1-2.4.2:1.1: GSM modem (1-port) converter detected
[1800785.978596] usb 1-2.4.2: GSM modem (1-port) converter now attached to ttyUSB1
[1800785.979220] option 1-2.4.2:1.2: GSM modem (1-port) converter detected
[1800785.979462] usb 1-2.4.2: GSM modem (1-port) converter now attached to ttyUSB2
[1800786.324071] scsi 3:0:0:0: CD-ROM ZTE USB SCSI CD-ROM 2.31 PQ: 0 ANSI: 2
[1800786.325395] scsi 3:0:0:1: Direct-Access ZTE MMC Storage 2.31 PQ: 0 ANSI: 2
[1800786.331560] sr 3:0:0:0: [sr1] scsi-1 drive
[1800786.359076] sr 3:0:0:0: Attached scsi CD-ROM sr1
[1800786.359210] sr 3:0:0:0: Attached scsi generic sg4 type 5
[1800786.359645] sd 3:0:0:1: Attached scsi generic sg5 type 0
[1800786.373392] sd 3:0:0:1: [sdc] 7716864 512-byte logical blocks: (3.95 GB/3.68 GiB)
[1800786.375021] sd 3:0:0:1: [sdc] Write Protect is off
[1800786.375026] sd 3:0:0:1: [sdc] Mode Sense: 0f 0e 00 00
[1800786.375768] sd 3:0:0:1: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[1800786.416178] sdc: sdc1
[1800786.435203] sd 3:0:0:1: [sdc] Attached SCSI removable disk
You can also use lsusb
to check that the device has been loaded.
$ lsusb | grep -i zte
Bus 001 Device 008: ID 19d2:0117 ZTE WCDMA Technologies MSM MF667
The device seems to show MF667
but the labeling says MF190
. Either way, they support the same commands for sending and receiving SMS.
For this post, we will disable both the CD-ROM and mass storage feature. It may so happen that you may want to take advantage of the mass storage feature to save messages or to use the USB GSM modem to receive files over GSM and that is out of the scope of this post.
First eject the CD-ROM from the host machine
$ sudo eject /dev/sr1
Then connect to the USB modem using a serial program like minicom
and run the following commands to disable the CD-ROM features. The first command makes the device online and the second command disables the CD-ROM auto-run feature.
$ minicom -b 115200 /dev/ttyUSB2
AT+ZOPRT=5
AT+ZCDRUN=8
Now the device is ready for sending and receiving messages and phone calls. For this post, we will not be making any phone calls.
Once the device has been setup and configured, let us try to use it using a Perl script. The GSM device acts like a modem with a serial port so the dependency that you need to install using the cpanm
tool is primarily Device::Gsm
which will install other dependencies like Device::Modem
and Device::SerialPort
. Of course, you could also use a Python script to connect to the modem, but we love writing Perl.
$ cpanm Device::Gsm Device::Modem Device::SerialPort
Sending messages can be done very easily using the Device::Gsm
module as shown below in the perl script. The $modem
, $text
and $recipient
variables must be edited as per your needs. The phone number must have no spaces, must include the country code and the +
sign in front of it.
Once you create a Device::Gsm
object, then you connect to the modem over the serial port /dev/ttyUSB2
with a baud rate of 115200. Once that connection works, you can then send a message using the send_sms
function which is obvious in the below code.
use strict;
use warnings;
use Device::Gsm;
## setup the USB GSM modem
my $modem = '/dev/ttyUSB2'; # or other like /dev/modem
my $gsm = Device::Gsm->new(port => $modem, log => 'file,/tmp/gsm.log',
loglevel => 'info');
$gsm->connect(115200) or die "Failed to connect to $modem";
## my message
my $text = "This is a test message";
## my phone number
my $recipient = '+12012012010'; # the full phone number you want to use
## send the message
my $sent = $gsm->send_sms(
content => substr($text, 0, 140),
recipient => $recipient,
);
die "Unable to send message to $recipient ", scalar localtime unless $sent;
print "Sent message to $recipient at ", scalar localtime, "\n";
Receiving messages is similarly done. You must connect to the modem at a baud rate of 115200 and then invoke the messages()
function with the storage option defined as ME
which stands for the phone memory, which is where the messages are stored by default on this ZTE device.
If you have messages stored in memory, the for
loop will get invoked and each message which is an instance of Device::Gsm::Sms
can then be handled or printed or processed or stored in a database etc. In the code below, we delete the message if the status is UNREAD
, but that is where the processing by the user can be done.
use strict;
use warnings;
use Device::Gsm;
use Device::Gsm::Sms;
## setup the USB GSM modem
my $modem = '/dev/ttyUSB2'; # or other like /dev/modem
my $gsm = Device::Gsm->new(port => $modem, log => 'file,/tmp/gsm.log',
loglevel => 'info');
$gsm->connect(115200) or die "Failed to connect to $modem";
## get the messages from the local storage 'ME'
my @messages = $gsm->messages('ME');
printf "You have %d messages\n", scalar(@messages);
my $idx = 0;
foreach my $msg (@messages) {
next unless defined $msg;
print '-' x 60, "\n", "MESSAGE N. $idx\n";
print 'Type ',($msg->type() eq Device::Gsm::Sms::SMS_SUBMIT ? 'SUBMIT' : 'DELIVER'), "\n";
print 'Status ', $msg->status(), "\n";
print 'From ', $msg->sender(), "\n";
print 'To ', $msg->recipient(), "\n";
print 'Time ', $msg->time(), "\n";
print 'Text [', $msg->text(), "]\n";
## if the message is unread, delete it now since you may have read it or
if ($msg->status() =~ /UNREAD/) {
### DO SOME PROCESSING HERE
print "DELETING SMS FROM STORAGE!!\n";
$msg->delete();
}
$idx++;
}
The received messages will look like the below:
------------------------------------------------------------
MESSAGE N. 0
Type DELIVER
Status REC UNREAD
From LYCAMOBILE
To
Text [Dear customer ,Your $19 INTERNATIONAL PLAN has been renewed succesfully.it is good through 09/16/2021. Visit https://www.lycamobile.us/login for details.]
------------------------------------------------------------
MESSAGE N. 1
Type DELIVER
Status REC UNREAD
From LYCAMOBILE
To
Text [ Thank you for using Lycamobile.]
------------------------------------------------------------
------------------------------------------------------------
MESSAGE N. 2
Type DELIVER
Status REC UNREAD
From +12012012010
To
Text [Test]
------------------------------------------------------------
MESSAGE N. 3
Type DELIVER
Status REC UNREAD
From +12012012010
To
Text [Got it]
------------------------------------------------------------
The below script lets you send a message to a recipient and receive replies by checking every 5 seconds. The most important thing to note is that you have to reconnect to the GSM modem if you have sent a message and then want to receive new messages. This forces the modem to exit the sending state and enter a receiving state.
The rest of the code is similar to the above code blocks in the earlier sections. This script was tested on Kali Linux and it works as of this writing.
#!/usr/bin/env perl
use strict;
use warnings;
use sigtrap qw/handler signal_handler normal-signals/;
use Device::Gsm;
use Device::Gsm::Sms;
use Data::Dumper;
sub usage {
die << "..."
Usage: $0 <phone number like +12125432109> <message>
Press Ctrl-C to exit program.
...
}
sub send_sms {
my ($gsm, $text, $recipient) = @_;
return unless length($text // '');
return unless $recipient;
my $sent = $gsm->send_sms(
content => substr($text, 0, 140),
recipient => $recipient,
);
die "Unable to send message to $recipient ", scalar localtime unless $sent;
print "Sent message to $recipient at ", scalar localtime, "\n";
}
sub receive_messages {
my $gsm = shift;
my @messages = $gsm->messages('ME');
printf "You have %d messages\n", scalar(@messages);
my $idx = 0;
foreach my $msg (@messages) {
next unless defined $msg;
print '-' x 60, "\n", "MESSAGE N. $idx\n";
print 'Type ',($msg->type() eq Device::Gsm::Sms::SMS_SUBMIT ? 'SUBMIT' : 'DELIVER'), "\n";
print 'Status ', $msg->status(), "\n";
print 'From ', $msg->sender(), "\n";
print 'To ', $msg->recipient(), "\n";
print 'Time ', $msg->time(), "\n";
print 'Text [', $msg->text(), "]\n";
if ($msg->status() =~ /UNREAD/) {
print "DELETING SMS FROM STORAGE!!\n";
$msg->delete();
}
$idx++;
}
}
sub signal_handler {
die "Signal caught: $!";
}
usage() unless scalar(@ARGV);
usage() unless defined $ARGV[0];#TODO: verify phone number format
usage() unless length($ARGV[1] // '');
warn "Message to be sent is longer than 140 chars and will be truncated" if length($ARGV[1]) > 140;
my $recipient = shift(@ARGV);
my $message = shift(@ARGV);
print "Using phone number $recipient for recipient\n";
my $modem = '/dev/modem';
$modem = '/dev/ttyACM0' if -e '/dev/ttyACM0';
$modem = '/dev/ttyUSB2' if -e '/dev/ttyUSB2';
my %log = (log => 'file,/tmp/gsm.log', loglevel => 'debug');
my $gsm = Device::Gsm->new(port => $modem, %log);
$gsm->connect(115200) or die "Failed to connect to $modem";
send_sms($gsm, $message, $recipient);
while (1) {
$gsm->connect(115200);
if ($gsm->is_active()) {
receive_messages($gsm);
sleep 5;
} else {
warn "GSM modem is not active";
last;
}
}
__END__
###
###
### COPYRIGHT: 2013-2021 Selective Intellect LLC. All Rights Reserved.
Want more information on gsm modems? Click the link below to contact us.