Friday, May 24, 2024

HMI - Human Machine Interface or Hacker Machine Interface - the vulnerability in the SCADA system - the entry of Rust...

Economic nuke on America - the Baltimore Bridge Collapse ...

Why we must upgrade our critical systems from legacy software which was not written keeping cyber attack in mind.

Watch...


In the early part of my software career, i worked on the Human Machine Interface (HMI) software of two different companies - Omron's NTWin and Mitsubishi's GOT.

As the Human Machine Interface or the HMI software used for SCADA were not written keeping cyber attacks on mind, they are just plain vulnerable to the hackers.

Within the various SCADA solutions, the HMI represents the clearest and most present target for attackers. The HMI acts as a centralised hub for managing critical infrastructure. If an attacker succeeds
in compromising the HMI, nearly anything can be done to the infrastructure itself, including causing physical damage to SCADA equipment. Even if attackers decide not to disrupt operations, they can still exploit the HMI to gather information about a system or disable alarms and notifications meant to alert operators of danger to SCADA equipment.

Read... Humans of Universe... Read...

Here is a document on the vulnerability of the HMI software.


From recent incidents in the USA - the vulnerability of HMI...

Oldsmar, Florida water treatment plant (2021): 

Attackers remotely accessed the HMI via insecure remote tools (e.g., TeamViewer with shared/default passwords) and tried to poison water by increasing sodium hydroxide levels.

Unitronics PLC/HMI hacks (2023 onward): 

IRGC-affiliated actors ("CyberAv3ngers") defaced HMI screens at U.S. water facilities and elsewhere by exploiting internet-exposed devices with default passwords ("1111"). please educate me on these two incidents 

And here we go - the sophisticated malware called Stuxnet - which was responsible for crippling the Iranian nuclear plant...

Can't believe?

Watch how it targeted the SIEMENS PLC at a nuclear plant in Iran.



Stuxnet was crafted to exploit specific vulnerabilities in Windows and the Siemens software stack. The worm utilized multiple zero-day exploits in Windows and targeted Siemens Step7 software running on Windows systems to reprogram PLCs. Since Stuxnet's payload and propagation mechanisms were tailored to this environment, a system running Linux would inherently be immune to these specific exploits.

You know that most legacy HMI software was written using C++, and memory corruption is one of the most common vulnerabilities in HMI software.



I, therefore, was just wondering about the suitability of usage of Rust instead of C++ for writing Human Machine Interface software as the former is designed to handle the memory corruption issue quite nicely.

And voila - my guess was correct...

Rust can be a compelling alternative to C++ for developing SCADA Human-Machine Interfaces (HMIs), especially considering the memory safety advantages Rust offers. Here are some key points on why Rust could be a better choice:

Memory Safety

Elimination of Common Vulnerabilities: 

Rust's design inherently prevents common memory-related issues such as buffer overflows, null pointer dereferencing, and use-after-free errors. These types of vulnerabilities are prevalent in systems programmed in C++.

Borrow Checker: 

Rust’s borrow checker enforces strict ownership and borrowing rules at compile-time, ensuring that memory safety issues are caught early in the development process, thereby reducing the risk of memory corruption in deployed systems.

Performance

Comparable to C++: Rust is designed to offer performance comparable to C and C++. It achieves this through zero-cost abstractions, meaning you can write high-level code without incurring a performance penalty.

Efficient Concurrency: Rust's concurrency model prevents data races at compile time, allowing for safe and efficient concurrent programming, which is crucial for the high reliability and performance required in SCADA systems.

Modern Language Features

Error Handling: Rust provides robust error handling mechanisms through its Result and Option types, promoting safer and more explicit error management compared to exceptions in C++.
Strong Type System: Rust’s strong and expressive type system helps catch more errors at compile time, reducing runtime bugs and improving overall code quality.

Ecosystem and Tooling

Growing Ecosystem: Rust’s ecosystem is rapidly growing, with many libraries and tools available for systems programming, networking, and interfacing with hardware, which are essential for SCADA systems.

Cargo: Rust’s package manager and build system, Cargo, simplifies dependency management, builds, and project organization, contributing to developer productivity and code maintainability.

Adoption and Community

Industry Adoption: While Rust is still relatively new compared to C++, it has been gaining traction in various industries, including embedded systems and safety-critical applications, demonstrating its suitability for high-reliability domains like SCADA.

Active Community: Rust has a vibrant and supportive community, which helps in quickly resolving issues, sharing best practices, and continuously improving the language and its ecosystem.

Challenges

Learning Curve: The main challenge in adopting Rust is its steep learning curve, especially for developers accustomed to C++. The concepts of ownership, borrowing, and lifetimes can take time to master.


In summary, Rust offers significant advantages in terms of memory safety, performance, and modern language features, making it a strong candidate for developing SCADA HMIs. Its ability to prevent common vulnerabilities associated with memory corruption makes it particularly appealing for the high-security requirements of SCADA systems.

And now as CrowdStrike hitting hard, the C++ memory exception is already in news.

Is null pointer exception the reason for CrowdStrike? see below...


Shall we move from C++ to Rust?

Tuesday, April 9, 2024

Observer pattern in Rust - driven by intrinsic motivation...


Work is worship...

 The observer design pattern is a very popular design pattern in the Object Oriented world. I must admit, I first saw the usefulness of this design pattern while studying the document view architecture of the MFC source code.

Later on, I used this pattern in many places.

There is a lot of similarity between the Observer Pattern, the Callback mechanism, and the Event Handler pattern in Java. Usually, the callback method is used when there is only one observer who awaits the signal from the subject.

So, let me put it in this fashion.

Suppose, there is a central document that is viewed by a few applications - someone is viewing it in a spreadsheet, someone as a Pie chart, and so on.

Now if the data in the document is updated, all the viewers must be updated and they should synchronise their views with the latest data set. So basically all the viewers were observing the central data. The moment it changes, all the observers get their respective views updated.

The class diagram and the sequence diagram of the observer pattern will be as follows.


Class Diagram




Sequence Diagram

Here goes an example of Observer Pattern written in Rust.


trait Observer {

fn update(&self,data:&str);

}


struct Subject<'a> {

observers: Vec<&'a dyn Observer>,

state: String,

}


impl<'a> Subject<'a> {

fn new(state: String) -> Self {

Self {

observers: Vec::new(),

state: state,

}

}


fn attach(&mut self, observer: &'a dyn Observer) {

self.observers.push(observer);

}


fn detach(&mut self, observer: &dyn Observer) {

self.observers.retain(|o| !std::ptr::eq(*o, observer));

}


fn notify(&self) {

for o in &self.observers {

o.update(&self.state);

}

}


fn set_state(&mut self, state: String) {

self.state = state;

self.notify();

}

}


struct ConcreteObserver {

name: String,

}




impl Observer for ConcreteObserver {

fn update(&self,data:&str) {

println!("{} received data: {}",self.name,data);

}

}



fn main() {

let mut subject = Subject::new("initial data".to_string());


let observer1=ConcreteObserver {

name: "Observer 1".to_string(),

};


let observer2=ConcreteObserver {

name: "Observer 2".to_string(),

};



subject.attach(&observer1);

subject.attach(&observer2);



subject.set_state("updated_data".to_string());


subject.detach(&observer2);


subject.set_state("Again updated data".to_string());


subject.detach(&observer1);

}


Explanation of Key Concepts:

Lifetimes ('a):

The lifetime 'a ties the lifetimes of the observers

to the lifetime of the Subject. This ensures that all observer

references in the vector remain valid as long as the Subject

exists.



Trait Objects (dyn Observer):

The dyn Observer in the Vec<&'a dyn Observer> denotes a trait

object. A trait object allows different types that implement

the Observer trait to be stored in the same collection (Vec).

This enables polymorphism, where the exact type of the observer

is determined at runtime.


Important Considerations

Lifetime Management:

Ensure that the lifetimes of all observers are correctly managed

to avoid dangling references.

Trait Object Overhead:

Using trait objects (dyn Trait) introduces some runtime overhead

due to dynamic dispatch.


&mut self:


  • &mut self in a method signature allows the method to modify the state of the object it's called on.
  • It’s part of Rust's strict ownership and borrowing rules, ensuring safe and concurrent access to data.
  • You must declare the instance as mutable (mut) to call such a method
  • Friday, March 29, 2024

    Adapter pattern in Rust - my exploration continues - in Rust, I keep my Trust...

     

    It's truly said that if you teach a person, actually two people learn.

    As a guru of my young son, Ridit, I taught him many design patterns and he implemented them in three different languages.

    Here's his discussion on Adaptor Design Pattern.

    Please go through his explanation.




    Today I implemented his work of Adapter Pattern using Rust.

    In Rust... I keep my Trust.

    Rust addresses memory safety and concurrency issues that plague other systems languages like C and C++. This makes it attractive for building reliable, high-performance systems.

    Rust is already being used in embedded systems, operating system kernels, and high-performance computing. Rust's memory safety makes it ideal for applications where security is paramount.

    In simple words, the future of Rust programming language looks bright.

    Here's the source code for the Adapter Design Pattern in Rust.

    use std::io;


    trait IWeatherFinder {

    fn get_temperature(&self, city_name : &str)-> i32;

    }


    struct WeatherFinder{}

    impl IWeatherFinder for WeatherFinder{

    fn get_temperature(&self, city_name : &str) -> i32{

    if (city_name.trim().eq("Kolkata".trim())){

    40

    }

    else{

    println!("Unknown City Name...Could not read temperature");

    -273

    }

    }

    }


    trait iWeatherFinderClient {

    fn get_temperature (&self, city_pincode : i32)->i32;

    }


    struct WeatherAdapter{}

    impl WeatherAdapter {

    fn get_city_name (&self, pincode : i32) -> &str {

    if pincode == 700078 {

    "Kolkata".trim()

    }

    else {

    "UnknownCity"

    }

    }

    fn get_temperature (&self, pincode : i32)-> i32 {

    let city_name = self.get_city_name(pincode);

    let weatherfinder : WeatherFinder = *Box::new(WeatherFinder{});

    weatherfinder.get_temperature(city_name)

    }

    }


    fn main() {

    println!("Enter pin code");

    let mut pincode = String::new();

    io::stdin().read_line(&mut pincode).expect("Failed to read line");

    let pin_code: i32 = pincode.trim().parse().expect("Input not an integer");

    let weatheradapter = WeatherAdapter{};

    let temperature: i32 = weatheradapter.get_temperature(pin_code);

    println!("The temparature is {} degree celcius", temperature);

    }


    Output:

    Enter pin code

    700078

    The temperature is 40 degree celcius

    Thursday, March 28, 2024

    Strategy Design Pattern in Rust...


    Karmyog - Work is worship...

    In Rust, i keep my Trust...

    The strategy design pattern is a behavioral design pattern that lets you dynamically switch the behavior of an object at runtime. It achieves this by separating the core functionality of the object from the specific algorithms it uses.

    Here's a breakdown of the core concepts:

    Strategy Interface: This interface defines the common operation that all the different algorithms will implement. This ensures that all the interchangeable strategies can be used by the context object.

    Concrete Strategies: These are the classes that implement the specific algorithms. Each concrete strategy class implements the strategy interface and provides its own unique behavior for the operation.

    Context Object: This object holds a reference to a strategy object and delegates the specific operation to it. It can change its behavior at runtime by switching the reference to a different concrete strategy.

    Here's an example of an UML diagram for the Strategy Design Pattern.



    In my code, the 

    trait TransportationToAirport{

    fn going_to_the_airport(&self);

    }

    plays the role of the Strategy interface.

    Three concrete Strategy classes have been derived from this interface  - namely, By_Ola, By_Bus and By_Rapido.

    These concrete strategy classes help to pick up a specific way for going to the airport dynamically, i.e.,  in runtime.

    Here's the source code for Strategy Pattern implemented in Rust.

    use std::io;


    trait TransportationToAirport{

    fn going_to_the_airport(&self);

    }


    struct By_Bus{}


    impl TransportationToAirport for By_Bus {

    fn going_to_the_airport(&self) {

    println!("Going to airport by Bus...");

    }

    }


    struct By_Ola{}



    impl TransportationToAirport for By_Ola{

    fn going_to_the_airport(&self) {

    println!("Going to airport by Ola...")

    }

    }


    struct By_Rapido{}


    impl TransportationToAirport for By_Rapido{

    fn going_to_the_airport(&self) {

    println!("Going to airport by Rapido...");

    }

    }



    struct Traveller{

    strategy : Box<dyn TransportationToAirport>,

    }


    impl Traveller{

    fn new(strategy: Box<dyn TransportationToAirport>) -> Self {

    Traveller { strategy }

    }

    fn travel(&self){

    self.strategy.going_to_the_airport();

    }

    pub fn set_strategy(&mut self, strategy: Box<dyn TransportationToAirport>) {

    self.strategy = strategy;

    }

    }



    fn main() {

    println!("Enter your choice...");

    let mut choice = String::new();

    io::stdin().read_line(&mut choice);

    if choice.trim().eq("BUS".trim()){

    let traveller : Traveller = Traveller::new(Box::new(By_Bus{}));

    traveller.travel();

    }

    if choice.trim().eq("OLA".trim()){

    let traveller : Traveller = Traveller::new(Box::new(By_Ola{}));

    traveller.travel();

    }

    if choice.trim().eq("RAPIDO".trim()){

    let traveller : Traveller = Traveller::new(Box::new(By_Rapido{}));

    traveller.travel();

    }

    }

    Here's the output of the above code:

    Enter your choice...

    OLA

    Going to airport by Ola...

    Monday, March 25, 2024

    Proxy design pattern in Rust - my exploration continues - Karmyog is the best way forward...



    Proxy pattern - as the name suggests - creates a proxy in place of a real heavy-duty object.

    Let me give you a real-life example taken from computer science.

    In case a document contains many huge-sized images, it does not load all the images when the doc gets loaded into the memory. Because it might take a very long time. 

    The proxy pattern comes as a rescue. 

    The document, instead of the actual mega images, gets loaded with very lightweight proxies of those images. And then when needed - in actual run time, i.e., when we need to see an image, the images get loaded by the proxy. This kind of proxy is called a virtual proxy.

    Now let us talk from our example.

    We are a family of three. Now my son does all the lightweight jobs - like, if there is a guest, he opens the door. So, he is the initial interface for the guests. However, in case, a guest wants to have lunch or dinner, my son calls his Mamma - because it's a heavy-duty job that he himself cannot do.

    So basically my son gives proxy to his Mom, and if needed - like when he has to perform a heavy-duty job like cooking - he simply delegates the task to his Mom. For all other lightweight jobs, his Mom, who obviously has a lot of significant jobs to perform, remains in the background. She comes in the foreground in case there is a heavy-duty task like cooking for a guest.

    Here's the UML class diagram of the proxy pattern.



    Now the source code of Proxy Pattern implemented in Rust

    Source Code

    trait Family{

    fn cook(&self);

    fn open_the_door(&self){

    println!("Son will handle Open The Door task");

    }

    }


    struct Mamma{}


    impl Family for Mamma {

    fn cook(&self){

    println!("Mamma is an expert cook..Mamma is cooking the food...");

    }

    }


    struct Son<'a > {

    mamma : & 'a Mamma,

    }


    impl <'a> Son<'a > {

    fn new (mamma : & 'a Mamma)-> Son {

    Son { mamma }

    }

    }


    impl <'a> Family for Son<'a> {

    fn cook(&self) {

    println!("Son cannot cook.... So he is passing the buck to Mamma");

    self.mamma.cook();

    }

    }


    fn main() {

        let mamma : Mamma = Mamma { };

    let son = Son :: new(&mamma);

    son.open_the_door();

    son.cook();

    }


    If we run the above code, the output will be like this:


    Son will handle Open The Door task

    Son cannot cook.... So he is passing the buck to Mamma

    Mamma is an expert cook..Mamma is cooking the food...


    Friday, March 22, 2024

    Factory Design Pattern in Rust - my exploration continues...


    Living a purposeful life - Karmyog... Salvation... Awakening...

    You know, the best way to learn a modern computer programming language is to apply the nuances in designing a real life problem. This way I learned C++, Java and Python. And now I am applying the same logic while picking up Rust.

    in Rust I keep my trust...

    So...

    here we go...

    A simple factory design pattern in Rust - my second program of Rust.

    Enjoy...

    Source Code:

    trait Food{

    fn display(&self);

    }


    enum FoodType{

    Chocolate,

    Biscuit,

    }


    struct Chocolate{}


    impl Food for Chocolate {

    fn display(&self) {

    println!("A chocolate is made...");

    }

    }


    struct Biscuit{}

    impl Food for Biscuit {

    fn display(&self){

    println!("A biscuit is made...");

    }

    }



    struct FoodFactory;

    impl FoodFactory{

    fn new_food (item:&FoodType) -> Box<dyn Food>{

    match item {

    FoodType::Chocolate => Box::new(Chocolate{}),

    FoodType::Biscuit => Box ::new(Biscuit{}),

    }

    }

    }

    fn main() {

    let food = FoodFactory::new_food(&FoodType::Chocolate);

    food.display();

    let food = FoodFactory::new_food(&FoodType::Biscuit);

    food.display();

    }

    Thursday, March 21, 2024

    My first program using Rust - delving into trait...


    चरैवेति, चरैवेति - Charaiveti, Charaiveti - keep walking...

    because the motion is the life - we need to move on to keep the balance of life...


    We must not stop.


    The movement is essential.


    Life is like a bicycle


    The moment it stops - the balance goes for a toss


    Life is like a stream.


    The moment the flow of the stream is lost, all sorts of fungi pollute the water - and the water becomes dirty and ceases to be a potable one.


    So, we have to keep moving all throughout our lives - physically - spiritually - and metaphorically - we must not stop the movement - because the


    Ultimate Stop comes with Death.


    So, here we go...


    After C++, Java and Python...


    my first program in Rust delving into trait - which is like an interface in Java or an abstract class of C++...


    The cornerstone of abstraction in Rust is traits:

    • Traits are Rust's sole notion of interface. A trait can be implemented by multiple types, and in fact new traits can provide implementations for existing types. 

    • Traits can be statically dispatched. Like C++ templates, you can have the compiler generate a separate copy of an abstraction for each way it is instantiated. Static dispatch generally results in faster code execution because there is no overhead associated with determining which function to call at runtime. The trade-off is that the code footprint will be larger.

    Here is an example of static dispatch.

    use std::any::type_name;

    trait Shape {
    fn area(&self) -> f64;
    }

    struct Circle {
    radius: f64,
    }

    struct Square {
    side: f64,
    }

    impl Shape for Circle {
    fn area(&self) -> f64 {
    3.14 * self.radius * self.radius
    }
    }

    impl Shape for Square {
    fn area(&self) -> f64 {
    self.side * self.side
    }
    }

    fn print_area<T: Shape>(shape: T) {
    println!("Area of : {} is {} :", type_name::<T>(), shape.area());
    }

    fn main() {
    let c = Circle { radius: 3.0 };
    let s = Square { side: 2.0 };

    print_area(c); // Statically dispatched to Circle's implementation of `area`
    print_area(s); // Statically dispatched to Square's implementation of `area`
    }

    • Traits can be dynamically dispatched. Sometimes you really do need an indirection, and so it doesn't make sense to "erase" an abstraction at runtime. The same notion of interface -- the trait -- can also be used when you want to dispatch at runtime.

    Source Code of dynamic dispatch:


    trait Animal {
    fn make_sound(&self);
    fn wag_tail(&self){

    println!("i don't have a tail...");
    }
    }

    struct Human{}

    impl Animal for Human {
    fn make_sound(&self) {
    println!("Human is speaking...");
    }
    }

    struct Dog {}

    impl Animal for Dog {

    fn make_sound(&self) {
    println!("Dog barks...");
    }

    fn wag_tail(&self) {
    println!("The dog is waging it's tail");
    }
    }

    fn main() {
    let dog = Box::new (Dog {});

    dog.make_sound();
    dog.wag_tail();

    let man = Box::new (Human {});
    man.make_sound();
    man.wag_tail();

    }


    The output:


    Dog barks... The dog is waging it's tail Human is speaking... i don't have a tail...